LocalPublicRankingForm.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. <?php
  2. /**
  3. * 重庆赤晓店信息科技有限公司
  4. * https://www.chixiaodian.com
  5. * Copyright (c) 2023 赤店商城 All rights reserved.
  6. */
  7. namespace app\modules\admin\models\localPublicRanking;
  8. use app\models\Option;
  9. use app\constants\OptionSetting;
  10. use app\models\User;
  11. use app\models\SaasUser;
  12. use app\models\Order;
  13. use app\models\Goods;
  14. use app\models\LocalPublicRankingUser;
  15. use app\models\LocalPublicRankingTask;
  16. use app\models\LocalPublicRankingGoods;
  17. use app\models\Coupon;
  18. class LocalPublicRankingForm extends Model {
  19. public $store_id;
  20. public $id;
  21. public $ids;
  22. public $goods_name;
  23. public $supplier_name;
  24. public $goods_id;
  25. public $cat_id;
  26. public $supplier_id;
  27. public $warehouse_id;
  28. public $warehouse_zone_id;
  29. public $is_delete;
  30. public $warning_num;
  31. public $eiId;
  32. public $eipId;
  33. public $nickname;
  34. public $phone;
  35. public $order_no;
  36. public $type;
  37. public $purchase_in_price;
  38. public function init() {
  39. parent::init();
  40. if (empty($this->store_id)) {
  41. $this->store_id = get_store_id();
  42. }
  43. }
  44. public static function afterOrderSave($order, $insert = 0, $changedAttributes = []) {
  45. try{
  46. $store_id = $order->store_id;
  47. if(!self::isopen($store_id)){
  48. return;
  49. }
  50. if(!$order->user_id){
  51. return;
  52. }
  53. $goods_id = self::isOrderInAct($order);
  54. if($order->is_pay && $goods_id){
  55. $doTask = LocalPublicRankingTask::doTask($store_id, $order->user_id, $order, $goods_id);
  56. debug_log([__LINE__, $store_id, $order->id, $insert, $doTask['data'] ? $doTask['data']->id : $doTask, $changedAttributes], __CLASS__ . '.log');
  57. }
  58. } catch (\Exception $ex) {
  59. \Yii::error($ex);
  60. debug_log([__LINE__, $order->id, $insert, $changedAttributes, $ex->getMessage()], __CLASS__ . '.log');
  61. return [
  62. 'code' => 1,
  63. 'msg' => $ex->getMessage(),
  64. ];
  65. }
  66. }
  67. public static function afterTaskSave($task, $insert = 0, $changedAttributes = []) {
  68. try{
  69. if ($insert) {
  70. //复购
  71. $price2Fugou = self::price2Fugou($task);
  72. debug_log([__LINE__, '复购', $task->id, $task->order_id, $price2Fugou], __CLASS__ . '.log');
  73. }
  74. } catch (\Exception $ex) {
  75. \Yii::error($ex);
  76. debug_log([__LINE__, $task->id, $ex->getMessage(), $changedAttributes], __CLASS__ . '.log');
  77. return [
  78. 'code' => 1,
  79. 'msg' => $ex->getMessage(),
  80. ];
  81. }
  82. }
  83. public static function afterPRUSave($pru, $insert = 0, $changedAttributes = []) {
  84. try{
  85. if ($insert) {
  86. //优惠券
  87. $sendCoupon = self::sendCoupon($pru);
  88. debug_log([__LINE__, '优惠券', $pru->id, $pru->user_id, $sendCoupon], __CLASS__ . '.log');
  89. }
  90. } catch (\Exception $ex) {
  91. \Yii::error($ex);
  92. debug_log([__LINE__, $pru->id, $ex->getMessage(), $changedAttributes], __CLASS__ . '.log');
  93. return [
  94. 'code' => 1,
  95. 'msg' => $ex->getMessage(),
  96. ];
  97. }
  98. }
  99. public static function checkMchList($store_id, $mch_list = []) {
  100. try{
  101. if(self::isopen($store_id)){
  102. $num = 0;
  103. $actGoods = null;
  104. foreach($mch_list as $mch){
  105. foreach($mch['goods_list'] as $goods){
  106. $num += $goods['num'];
  107. if(!$actGoods){
  108. $actGoods = self::actGoods($goods['id']);
  109. if($actGoods){
  110. $actGoods = $goods;
  111. }
  112. }
  113. }
  114. }
  115. if($actGoods && $num > 1){
  116. throw new \Exception('商城公排活动商品只能单独购买,商品名称:' . $actGoods['goods_name']);
  117. }
  118. }
  119. return [
  120. 'code' => 0,
  121. ];
  122. } catch (\Exception $ex) {
  123. \Yii::error($ex);
  124. debug_log([__LINE__, $mch_list, $ex->getMessage()], __CLASS__ . '.log');
  125. return [
  126. 'code' => 1,
  127. 'msg' => $ex->getMessage(),
  128. ];
  129. }
  130. }
  131. public static $confs = [];
  132. public static function conf($store_id = 0, $refresh = 0) {
  133. if (isset(self::$confs[$store_id]) && !$refresh) {
  134. return self::$confs[$store_id];
  135. }
  136. $confDef = [
  137. 'is_open' => 0,
  138. //规则
  139. 'PublicRankingRow' => 0, //3人公排(33公排)或2人公排(22公排) ○若已有公排点位,不可修改此项
  140. 'firstPriceParent' => 0, //首单奖励 1直推人 0公排上级
  141. //复购
  142. 'price2Fugou' => '', //强制复购金额:佣金达到强制复购金额后,需重新完成任务,保完成后才能获得对应层级奖金
  143. 'price2FugouAmount' => '', //复购金额:备注:当用户达到强制复购金额后必须完成规定的复购金额后才能重新开始获得佣金
  144. //躺赚
  145. 'auto_price_child_cnt' => '', //躺赚直推人数
  146. 'auto_price_wait_days' => '', //躺赚直推等待天数
  147. //推荐奖励活动
  148. 'coupon_child_user_count' => '', //直推人数
  149. 'coupon_count' => '',
  150. 'coupon_id' => '',
  151. ];
  152. $conf = Option::get(OptionSetting::LOCAL_PUBLIC_RANKING_SETTING, $store_id, 'store')['value'];
  153. if ($conf) {
  154. $conf = array_merge($confDef, json_decode($conf, true));
  155. } else {
  156. $conf = $confDef;
  157. }
  158. self::$confs[$store_id] = $conf;
  159. return $conf;
  160. }
  161. public static function confSave($store_id = 0, $config = []) {
  162. $oldConf = self::conf($store_id, 1);
  163. $conf = array_merge($oldConf, $config);
  164. $set = Option::set(OptionSetting::LOCAL_PUBLIC_RANKING_SETTING, json_encode($conf, JSON_UNESCAPED_UNICODE), $store_id, 'store');
  165. self::conf($store_id, 1);
  166. return [
  167. 'code' => 0,
  168. 'msg' => 'ok',
  169. '$save' => $set,
  170. ];
  171. }
  172. public static function isopen($store_id = 0) {
  173. $conf = self::conf($store_id);
  174. if(!$conf['PublicRankingRow']){
  175. return 0;
  176. }
  177. //规定:默认开启,不能关闭
  178. return 1;
  179. $isopen = $conf['is_open'];
  180. return empty($isopen) ? 0 : 1;
  181. }
  182. //躺赚
  183. public static function isAutoPriceSuccess($store_id, $user_id) {
  184. $publicRankingUser = LocalPublicRankingUser::findOne(['user_id' => $user_id]);
  185. $conf = self::conf($store_id);
  186. $conf_auto_price_child_cnt = $conf['auto_price_child_cnt'];
  187. $conf_auto_price_wait_days = $conf['auto_price_wait_days'];
  188. if($conf_auto_price_child_cnt <= 0){
  189. return true;
  190. }
  191. if($conf_auto_price_wait_days > 0 && ($publicRankingUser['created_at'] > (time() - 86400 * $conf_auto_price_wait_days))){
  192. return true;
  193. }
  194. $childCnt = LocalPublicRankingUser::find()->where(['user_id' => User::find()->select('id')->where(['old_parent_id' => $user_id])])->count();
  195. if($childCnt >= $conf_auto_price_child_cnt){
  196. return true;
  197. }
  198. return false;
  199. }
  200. //复购
  201. public static function price2Fugou(LocalPublicRankingTask $task) {
  202. $store_id = $task->store_id;
  203. debug_log([__LINE__, '检测复购', $store_id, $task['id'], $task['order_id']], __CLASS__ . '.log');
  204. $parent_user_id = $task->parent_user_id;
  205. if(!$parent_user_id){
  206. return null;
  207. }
  208. $conf = self::conf($store_id);
  209. $conf_price2Fugou = $conf['price2Fugou'];
  210. if($conf_price2Fugou <= 0){
  211. debug_log([__LINE__, '强制复购金额未配置', $store_id, $parent_user_id], __CLASS__ . '.log');
  212. return null;
  213. }
  214. $priceTotal = LocalPublicRankingTask::priceTotal($store_id, $parent_user_id, 0);
  215. if($priceTotal >= $conf_price2Fugou){
  216. $t = \Yii::$app->db->beginTransaction();
  217. try {
  218. $parent_pru = LocalPublicRankingUser::findOne(['user_id' => $parent_user_id]);
  219. $updateAll = LocalPublicRankingTask::updateAll(['has_fugou' => 1], ['store_id' => $store_id, 'parent_user_id' => $parent_user_id, 'has_fugou' => 0, 'status' => 1]);
  220. $parent_pru->is_fugou = 1;
  221. if(!$parent_pru->save()){
  222. throw new \Exception(array_shift($parent_pru->getFirstErrors()));
  223. }
  224. $t->commit();
  225. debug_log([__LINE__, '检测复购 加状态', $task->id, $updateAll, '$pru->is_fugou = 1', $parent_user_id], __CLASS__ . '.log');
  226. return true;
  227. } catch (\Exception $e) {
  228. $t->rollBack();
  229. \Yii::error($e);
  230. debug_log([__LINE__, '检测复购', $store_id, $task->id, $e->getMessage()], __CLASS__ . '.log');
  231. }
  232. }
  233. return false;
  234. }
  235. //复购完成
  236. public static function isFugouFinish($store_id, $user_id) {
  237. $conf = self::conf($store_id);
  238. $price2FugouAmount = $conf['price2FugouAmount'];
  239. $payTotal = LocalPublicRankingTask::payTotal($store_id, $user_id, 0);
  240. if($payTotal >= $price2FugouAmount){
  241. return true;
  242. }
  243. return false;
  244. }
  245. //优惠券
  246. public static function sendCoupon(LocalPublicRankingUser $pru) {
  247. $store_id = $pru->store_id;
  248. $user = User::findOne($pru['user_id']);
  249. $parent_user_id = $user['old_parent_id'];
  250. debug_log([__LINE__, '检测优惠券', $store_id, $pru['id'], $pru['user_id'], $parent_user_id], __CLASS__ . '.log');
  251. if(!$parent_user_id){
  252. return null;
  253. }
  254. $pruParent = LocalPublicRankingUser::findOne(['user_id' => $parent_user_id]);
  255. if(!$pruParent){
  256. return null;
  257. }
  258. $conf = self::conf($store_id);
  259. $coupon_child_user_count = $conf['coupon_child_user_count'];
  260. $coupon_count = $conf['coupon_count'];
  261. $coupon_id = $conf['coupon_id'];
  262. if(!$coupon_child_user_count || !$coupon_count || !$coupon_id){
  263. return null;
  264. }
  265. $child_user_cnt = (int)LocalPublicRankingUser::find()->where(['user_id' => User::find()->select('id')->where(['old_parent_id' => $parent_user_id])])->count();
  266. if($child_user_cnt != $coupon_child_user_count){
  267. return null;
  268. }
  269. for ($i = 0; $i < $coupon_count; $i++) {
  270. $use_coupon = Coupon::userAddCoupon($parent_user_id, $coupon_id);
  271. debug_log([__LINE__, '发优惠券', $store_id, $parent_user_id, $coupon_id, $use_coupon], __CLASS__ . '.log');
  272. }
  273. return $use_coupon;
  274. }
  275. //订单是否是活动商品
  276. public static function isOrderInAct($order) {
  277. $detail = $order->detail;
  278. if(count($detail) == 1){
  279. $det = $detail[0];
  280. $goods_id = $det['goods_id'];
  281. $actGoods = LocalPublicRankingGoods::findOne(['goods_id' => $goods_id, 'status' => 1]);
  282. if($actGoods){
  283. return $goods_id;
  284. }
  285. }
  286. return false;
  287. }
  288. //活动商品
  289. public static function actGoods($goods_id = null) {
  290. return LocalPublicRankingGoods::findOne(['goods_id' => $goods_id, 'status' => 1]);
  291. }
  292. public static function publicRankingGoodsList($store_id, $params = []) {
  293. $query = LocalPublicRankingGoods::find()->where(['store_id' => $store_id]);
  294. if(isset($params['status']) && $params['status'] >= 0){
  295. $query->andWhere(['status' => $params['status']]);
  296. }
  297. if($params['name']){
  298. $query->andWhere(['goods_id' => Goods::find()->select('id')->where(['like', 'name', $params['name']])]);
  299. }
  300. $query->orderBy('id DESC');
  301. $data = pagination_make($query);
  302. foreach($data['list'] as &$item){
  303. $item['goods'] = Goods::findOne($item['goods_id']);
  304. }
  305. return [
  306. 'code' => 0,
  307. 'msg' => 'ok',
  308. 'data' => $data,
  309. ];
  310. }
  311. /**
  312. * 商品保存
  313. */
  314. public static function publicRankingGoodsSave($store_id, $goods_id, $commission_amount = 0) {
  315. try {
  316. $goodsExt = LocalPublicRankingGoods::findOne(['goods_id' => $goods_id, 'store_id' => $store_id]);
  317. if (!$goodsExt) {
  318. $goodsExt = new LocalPublicRankingGoods();
  319. $goodsExt->store_id = $store_id;
  320. $goodsExt->goods_id = $goods_id;
  321. $goodsExt->status = 1;
  322. }
  323. $goodsExt->commission_amount = $commission_amount;
  324. if (!$goodsExt->save()) {
  325. \Yii::error([__METHOD__, $goodsExt->attributes]);
  326. throw new \Exception('保存失败。' . array_shift($goodsExt->getFirstErrors()));
  327. }
  328. return [
  329. 'code' => 0,
  330. 'msg' => '操作成功!'
  331. ];
  332. } catch (\Exception $e) {
  333. \Yii::error($e);
  334. return [
  335. 'code' => 1,
  336. 'msg' => $e->getMessage()
  337. ];
  338. }
  339. }
  340. /**
  341. * 商品分红状态
  342. */
  343. public static function publicRankingGoodsStatus($id, $status) {
  344. if (!is_array($id)) {
  345. $id = explode(',', $id);
  346. }
  347. LocalPublicRankingGoods::updateAll(['status' => $status], ['id' => $id]);
  348. return [
  349. 'code' => 0,
  350. 'msg' => 'success',
  351. ];
  352. }
  353. /**
  354. * 商品删除
  355. */
  356. public static function publicRankingGoodsDel($id) {
  357. if (!is_array($id)) {
  358. $id = explode(',', $id);
  359. }
  360. LocalPublicRankingGoods::deleteAll(['id' => $id]);
  361. return [
  362. 'code' => 0,
  363. 'msg' => 'success',
  364. ];
  365. }
  366. public static function publicRankingTaskList($store_id, $params = []) {
  367. $query = LocalPublicRankingTask::find()->where(['store_id' => $store_id]);
  368. if(isset($params['status']) && $params['status'] >= 0){
  369. $query->andWhere(['status' => $params['status']]);
  370. }
  371. if($params['user_id']){
  372. $query->andWhere(['user_id' => $params['user_id']]);
  373. }
  374. if($params['parent_user_id']){
  375. $query->andWhere(['parent_user_id' => $params['parent_user_id']]);
  376. }
  377. $query->orderBy('id DESC');
  378. $data = pagination_make($query);
  379. foreach($data['list'] as &$item){
  380. $item['user'] = User::findOne($item['user_id']);
  381. $item['order'] = Order::findOne($item['order_id']);
  382. $item['order_detail'] = $item['order'] ? $item['order']->detail : null;
  383. }
  384. return [
  385. 'code' => 0,
  386. 'msg' => 'ok',
  387. 'data' => $data,
  388. ];
  389. }
  390. public static function publicRankingUserList($store_id, $params = []) {
  391. $conf = self::conf($store_id);
  392. $query = LocalPublicRankingUser::find()->where(['store_id' => $store_id]);
  393. if($params['user_name']){
  394. $query->andWhere(['user_id' => User::find()->select('id')->where(['like', 'nickname', $params['user_name']])]);
  395. }
  396. if($params['mobile']){
  397. $query->andWhere(['user_id' => User::find()->select('id')->where(['like', 'binding', $params['mobile']])]);
  398. }
  399. if($params['time_begin']){
  400. $query->andWhere(['>=', 'created_at', strtotime($params['time_begin'])]);
  401. }
  402. if($params['time_end']){
  403. $query->andWhere(['<=', 'created_at', strtotime($params['time_end'])]);
  404. }
  405. if(isset($params['sort']) && $params['sort'] > 0){
  406. if(strpos($params['sort'], '-')){
  407. $params['sort'] = LocalPublicRankingUser::posToSort($params['sort'], $conf['PublicRankingRow']);
  408. }
  409. $query->andWhere(['sort' => trim($params['sort'])]);
  410. }
  411. $query->orderBy('sort');
  412. $data = pagination_make($query);
  413. foreach($data['list'] as &$item){
  414. $item['user'] = User::findOne($item['user_id']);
  415. $item['saas_user'] = $item['user'] ? SaasUser::findOne(['mobile' => $item['user']['binding']]) : null;
  416. $buyOrderCnt = (int)LocalPublicRankingTask::find()->where(['user_id' => $item['user_id']])->count();
  417. $item['buy_order_cnt'] = $buyOrderCnt;
  418. $buyOrderSum = (float)Order::find()->where(['id' => LocalPublicRankingTask::find()->select('order_id')->where(['user_id' => $item['user_id']])])->sum('pay_price');
  419. $item['buy_order_sum'] = $buyOrderSum;
  420. $childOrderCnt = (int)LocalPublicRankingTask::find()->where(['parent_user_id' => $item['user_id']])->count();
  421. $item['child_order_cnt'] = $childOrderCnt;
  422. $commission_amount = (float)LocalPublicRankingTask::find()->where(['parent_user_id' => $item['user_id']])->sum('commission_amount');
  423. $item['commission_amount'] = $commission_amount;
  424. $child_user_cnt = (int)LocalPublicRankingUser::find()->where(['user_id' => User::find()->select('id')->where(['old_parent_id' => $item['user_id']])])->count();
  425. $item['child_user_cnt'] = $child_user_cnt;
  426. $item['getPos'] = LocalPublicRankingUser::getPos($item['sort'], $conf['PublicRankingRow']);
  427. }
  428. return [
  429. 'code' => 0,
  430. 'msg' => 'ok',
  431. 'data' => $data,
  432. ];
  433. }
  434. public static function publicRankingUserIndex($store_id, $user_id) {
  435. try{
  436. if(!self::isopen($store_id)){
  437. throw new \Exception('商城功能未开启');
  438. }
  439. $conf = self::conf($store_id);
  440. $taskFinshCount = LocalPublicRankingTask::find()->where(['store_id' => $store_id, 'user_id' => $user_id, 'status' => 1])->count();
  441. $user = User::findOne($user_id);
  442. $publicRankingUser = LocalPublicRankingUser::findOne(['user_id' => $user_id]);
  443. if($publicRankingUser && $publicRankingUser->sort > 1){
  444. $psort = LocalPublicRankingUser::getParentSorts($publicRankingUser->sort, $conf['PublicRankingRow'], 1);
  445. $publicRankingUserParent = LocalPublicRankingUser::findOne(['store_id' => $store_id, 'sort' => $psort]);
  446. $publicRankingUserParentUser = $publicRankingUserParent->user_id ? User::findOne($publicRankingUserParent->user_id) : null;
  447. }
  448. $parentUser = $user->old_parent_id ? User::findOne($user->old_parent_id) : null;
  449. $isAutoPriceSuccess = self::isAutoPriceSuccess($store_id, $user_id);
  450. $isPriceSuccess = !$publicRankingUser->is_fugou && $isAutoPriceSuccess;
  451. $child_user_cnt = (int)LocalPublicRankingUser::find()->where(['user_id' => User::find()->select('id')->where(['old_parent_id' => $user_id])])->count();
  452. return [
  453. 'code' => 0,
  454. 'data' => [
  455. 'conf' => $conf,
  456. 'publicRankingUserParentUser' => $publicRankingUserParentUser,
  457. 'parentUser' => $parentUser,
  458. 'publicRankingUser' => $publicRankingUser,
  459. 'user' => $user,
  460. 'saas_user' => get_saas_user(),
  461. 'taskFinshCount' => $taskFinshCount,
  462. 'isAutoPriceSuccess' => $isAutoPriceSuccess,
  463. 'isPriceSuccess' => $isPriceSuccess,
  464. 'child_user_cnt' => $child_user_cnt,
  465. 'getPos' => LocalPublicRankingUser::getPos($publicRankingUser['sort'], $conf['PublicRankingRow']),
  466. ],
  467. ];
  468. } catch (\Exception $e) {
  469. \Yii::error($e);
  470. debug_log([__LINE__, $e->getMessage()], __CLASS__ . '.log');
  471. return [
  472. 'code' => 1,
  473. 'msg' => '操作失败,' . $e->getMessage()
  474. ];
  475. }
  476. }
  477. }