Distribution.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. <?php
  2. namespace addons\Distribution\common\models;
  3. use addons\Distribution\common\enums\DistributionEnum;
  4. use common\enums\AddonsEnum;
  5. use common\enums\StatusEnum;
  6. use common\models\base\BaseActiveRecord;
  7. use common\models\common\Addons;
  8. use common\models\common\CapitalLog;
  9. use common\models\common\Download;
  10. use common\enums\DownloadEnum;
  11. use common\models\mall\MallAddons;
  12. use common\models\user\User;
  13. use common\models\user\UserPartitionRelationship;
  14. use Exception;
  15. use Yii;
  16. use common\components\export\CsvTool;
  17. use common\enums\RedisKeyEnum;
  18. use common\helpers\ArrayHelper;
  19. use common\helpers\LockHelper;
  20. /**
  21. * This is the model class for table "{{%addons_distribution}}".
  22. *
  23. * @property int $id
  24. * @property int $mall_id
  25. * @property int $user_id
  26. * @property string|null $remarks 备注
  27. * @property int $status
  28. * @property int $created_at 创建时间
  29. * @property int $updated_at 修改时间
  30. * @property int $level 分销商等级
  31. * @property int $upgrade_level_at 分销商等级升级时间
  32. * @property float $total_commission 佣金
  33. * @property float $total_score 积分
  34. * @property float $total_digital 累计数字币
  35. * @property User $user
  36. * @property int $upgrade_status
  37. *
  38. * @property DistributionLevel $distributionLevel
  39. */
  40. class Distribution extends BaseActiveRecord
  41. {
  42. const UPGRADE_STATUS_CONDITION = 1;
  43. const UPGRADE_STATUS_GOODS = 2;
  44. const UPGRADE_STATUS_MANUAL = 3;
  45. /**
  46. * {@inheritdoc}
  47. */
  48. public static function tableName()
  49. {
  50. return '{{%addons_distribution}}';
  51. }
  52. /**
  53. * {@inheritdoc}
  54. */
  55. public function rules()
  56. {
  57. return [
  58. [['mall_id', 'user_id'], 'required'],
  59. [['mall_id', 'user_id', 'status', 'created_at', 'updated_at', 'level', 'upgrade_level_at', 'upgrade_status','is_height_commission'], 'integer'],
  60. [['remarks'], 'string'],
  61. [['total_commission','height_commission','total_score', ], 'number'],
  62. [['total_digital'],'number']
  63. ];
  64. }
  65. /**
  66. * {@inheritdoc}
  67. */
  68. public function attributeLabels()
  69. {
  70. return [
  71. 'id' => 'ID',
  72. 'mall_id' => 'Mall ID',
  73. 'user_id' => 'User ID',
  74. 'remarks' => '备注',
  75. 'status' => '状态[-1:删除;0:禁用;1启用]',
  76. 'created_at' => '创建时间',
  77. 'updated_at' => '修改时间',
  78. 'level' => '分销商等级',
  79. 'upgrade_level_at' => '分销商等级升级时间',
  80. 'total_commission' => '总佣金',
  81. 'total_score' => '总佣金',
  82. 'upgrade_status' => '升级方式,1条件升级 2 购买指定商品升级 3手动升级',
  83. 'total_digital' => '总数字币',
  84. ];
  85. }
  86. public function getUser()
  87. {
  88. return $this->hasOne(User::class, ['id' => 'user_id']);
  89. }
  90. public function getDistributionLevel()
  91. {
  92. return $this->hasOne(DistributionLevel::class, ['level' => 'level','mall_id'=>'mall_id'])->where(['status' => StatusEnum::ENABLED]);
  93. }
  94. public function afterSave($insert, $changedAttributes)
  95. {
  96. // TODO:事件暂时不做处理
  97. return parent::afterSave($insert, $changedAttributes); // TODO: Change the autogenerated stub
  98. }
  99. /**
  100. * @desc:保存数据
  101. * @Author: hua
  102. * @Date: 2021/10/23
  103. * @Time: 18:07
  104. * @Copyright: copyright (c) 2021 广东七件事集团
  105. * @param array $params
  106. * @return Distribution|false|null
  107. */
  108. public static function setData(array $params)
  109. {
  110. try {
  111. if (!empty($params['id'])) {
  112. $model = self::findOne(['mall_id' => $params['mall_id'], 'id' => $params['id'], 'status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]]);
  113. if (empty($model)) throw new \Exception('服务不存在或已删除');
  114. } else {
  115. $model = new self();
  116. $model->loadDefaultValues();
  117. }
  118. if (!$model->load($params, '')) throw new \Exception($model->getErrorMessage());
  119. if (!$model->save()) throw new Exception($model->getErrorMessage());
  120. return $model;
  121. } catch (\Exception $e) {
  122. self::$static_error = $e->getMessage();
  123. return false;
  124. }
  125. }
  126. /**
  127. * @desc:导出字段
  128. * @param array|null $field
  129. * @Author: hua
  130. * @Date: 2021/10/23
  131. * @Time: 18:03
  132. * @Copyright: copyright (c) 2021 广东七件事集团
  133. * @return \string[][]
  134. */
  135. public static function exportFieldsList($field = null)
  136. {
  137. $fields = [
  138. 'a.user_id' => '用户ID',
  139. 'u.nickname' => '昵称',
  140. 'u.mobile' => '手机号',
  141. 'a.created_at' => '成为分销商时间',
  142. 'a.total_commission' => '累计佣金',
  143. 'a.level' => '分销商等级',
  144. 'u.nickname parent_name' => '推荐人',
  145. 'a.remarks' => '备注信息'
  146. ];
  147. $temp = [];
  148. foreach ($fields as $key => $val) {
  149. $showField = explode('.', $key)[1];
  150. if (strstr($showField, ' ')) {
  151. $showField = explode(' ', $showField)[1];
  152. }
  153. if ($field === null) {
  154. $temp[$showField] = $val;
  155. } else if (in_array($showField, $field)) {
  156. $temp[$key] = $val;
  157. }
  158. }
  159. return $temp;
  160. }
  161. public static function fieldsList($field = null)
  162. {
  163. $fields = [
  164. 'user_id' => '用户ID',
  165. 'nickname' => '昵称',
  166. 'mobile' => '手机号',
  167. 'created_at' => '成为分销商时间',
  168. 'total_commission' => '累计佣金',
  169. 'level' => '分销商等级',
  170. 'parent_name' => '推荐人',
  171. 'remarks' => '备注信息',
  172. ];
  173. if ($field === null) return $fields;
  174. $temp = [];
  175. foreach ($field as $val) {
  176. if (isset($fields[$val])) $temp[$val] = $fields[$val];
  177. }
  178. return $temp;
  179. }
  180. /**
  181. * @name:
  182. * @msg: 处理导出数据,这个方法是异步队列处理时使用的,请别修改
  183. * @param {array} $data
  184. * @return bool
  185. */
  186. public static function exportHandle(array $data)
  187. {
  188. $download_id = $data['download_id'] ?? 0;
  189. $download = Download::findOne(['id' => $download_id]);
  190. if ($download) {
  191. try {
  192. $params = json_decode($download->params, true);
  193. $filename = $download->name;
  194. $type = $download->type;
  195. $fields = $params['fields'];
  196. $fields_arr = self::fieldsList();
  197. $have_select_field_arr = [];
  198. foreach ($fields as $value) {
  199. $have_select_field_arr[] = $fields_arr[$value];
  200. }
  201. $csv = new CsvTool();
  202. $csv->filename = $filename;
  203. $csv->file_dirname = DownloadEnum::getTypeStorageDirMap($type);
  204. $csv->export_mode = CsvTool::EXPORT_MODE_ASYNC;
  205. $csv->header = $have_select_field_arr;
  206. $model = self::find();
  207. $model->where(['mall_id' => $params['mall_id']]);
  208. $model->andWhere(['>=', 'status', StatusEnum::DISABLED]);
  209. $user_id = 0;
  210. $user_id_arr = [];
  211. //拼接查询条件
  212. if (!empty($params['user_id'])) $user_id = $params['user_id'];
  213. if (!empty($params['level'])) $model->andWhere(['=', 'level', $params['level']]);
  214. if (!empty($params['keyword'])) {
  215. $condition['where'] = [[
  216. 'or',
  217. ['like', 'username', $params['keyword']],
  218. ['like', 'nickname', $params['keyword']],
  219. ['like', 'mobile', $params['keyword']]
  220. ]];
  221. $user_list = User::lists($condition);
  222. $user_id_arr = array_column($user_list, 'id');
  223. }
  224. if ($user_id && $user_id_arr) {
  225. $user_ids = array_intersect([$user_id], $user_id_arr);
  226. $model->andWhere(['in', 'user_id', $user_ids]);
  227. } else if ($user_id) {
  228. $model->andWhere(['in', 'user_id', $user_id]);
  229. } elseif ($user_id_arr) {
  230. $model->andWhere(['in', 'user_id', $user_id_arr]);
  231. }
  232. $model->with(['user', 'distributionLevel']);//关联查询
  233. $configs = \Yii::$app->services->setting->addons->get($params['mall_id'], AddonsEnum::ADDONS_NAME_DISTRIBUTION, 'basic');
  234. $level_name = $configs['default_level_name'] ?? '默认等级';
  235. //遍历组装数据
  236. foreach ($model->batch() as $list) {
  237. $parent_id_arr = $parent_arr = [];
  238. //查询上级昵称数组
  239. if (in_array('parent_name', $fields)) {
  240. foreach ($list as $item) {
  241. $parent_id_arr[] = $item['user']['parent_id'];
  242. }
  243. $parent_arr = UserPartitionRelationship::getParentsNickname($parent_id_arr);
  244. }
  245. $csv->data = array_map(function ($distribution) use ($fields, $parent_arr,$level_name) {
  246. $row = [];
  247. //遍历所选字段
  248. foreach ($fields as $field) {
  249. if (in_array($field, ['created_at'])) {
  250. $row[] = !empty($distribution[$field]) ? date('Y-m-d H:i:s', $distribution[$field]) : '';
  251. } elseif (in_array($field, ['nickname', 'mobile'])) {
  252. $row[] = !empty($distribution['user'][$field]) ? $distribution['user'][$field] : '';
  253. } elseif (in_array($field, ['level'])) {
  254. $row[] = !empty($distribution['distributionLevel']['name']) ? $distribution['distributionLevel']['name'] : $level_name;
  255. } elseif (in_array($field, ['parent_name'])) {
  256. $row[] = !empty($parent_arr[$distribution['user']['parent_id']]) ? $parent_arr[$distribution['user']['parent_id']] : '平台';
  257. } else {
  258. $row[] = !empty($distribution[$field]) ? $distribution[$field] : '';
  259. }
  260. }
  261. return $row;
  262. }, $list);
  263. $csv->export();
  264. }
  265. //上传云存储
  266. $csv->updateDown($download, $params['mall_id']);
  267. return true;
  268. } catch (Exception $e) {
  269. $download->status = 3;
  270. $res = $download->save();
  271. self::setStaticError($e->getMessage());
  272. return false;
  273. }
  274. }
  275. }
  276. /**
  277. * @desc:批量修改等级
  278. * @Author: hua
  279. * @Date: 2021/10/29
  280. * @Time: 10:39
  281. * @Copyright: copyright (c) 2021 广东七件事集团
  282. * @param $params
  283. * @return bool
  284. */
  285. public static function batchLevel($params)
  286. {
  287. try {
  288. if (isset($params['level']) && !empty($params['level'])) {
  289. $args = [];
  290. $args['where'] = [['mall_id' => $params['mall_id']], ['level' => $params['level']], ['status' => StatusEnum::ENABLED]];
  291. $args['select'] = 'id,level,name';
  292. $agentList = DistributionLevel::lists($args, true);
  293. if (empty($agentList)) throw new \Exception('无效的经销商等级');
  294. } else {
  295. $params['level'] = 0;
  296. }
  297. self::updateAll(
  298. ['level' => $params['level'], 'upgrade_level_at' => time(), 'upgrade_status' => DistributionEnum::UPGRADE_STATUS_MANUAL, 'updated_at' => time()],
  299. ['id' => $params['batch_ids']]
  300. );
  301. return true;
  302. } catch (\Exception $e) {
  303. self::$static_error = $e->getMessage();
  304. return false;
  305. }
  306. }
  307. public static function getParams($getData)
  308. {
  309. $params = [];
  310. if (isset($getData['user_id']) && !empty($getData['user_id'])) $params['where'][] = ['=', 'u.id', $getData['user_id']];
  311. if (isset($getData['level']) && !empty($getData['level'])) $params['where'][] = ['=', 'a.level', $getData['level']];
  312. if (isset($getData['keyword']) && !empty($getData['keyword'])) {
  313. $params['where'] = [[
  314. 'or',
  315. ['like', 'u.username', $getData['keyword']],
  316. ['like', 'u.nickname', $getData['keyword']],
  317. ['like', 'u.mobile', $getData['keyword']]
  318. ]];
  319. }
  320. $params['where'][] = ['=', 'a.mall_id', $getData['mall_id']];
  321. $params['where'][] = ['in', 'a.status', [StatusEnum::ENABLED, StatusEnum::DISABLED]];
  322. $params['alias'] = 'a';
  323. $params['join'] = [['LEFT JOIN', User::tableName() . ' up', "up.id = u.parent_id"]];
  324. $params['joinWith'] = ['user' => function ($query) {
  325. $query->from(['u' => User::tableName()]);
  326. }];
  327. return $params;
  328. }
  329. /**
  330. * @desc:推广中心-调用
  331. * @Author: hua
  332. * @Date: 2021/11/12
  333. * @Time: 9:30
  334. * @Copyright: copyright (c) 2021 广东七件事集团
  335. * @param array $params ['user_id' => 1, 'mall_id' => 5, 'addons_name' => 'Agent']
  336. * @return array
  337. */
  338. public static function getIncomeInfo(array $params)
  339. {
  340. $is_install = MallAddons::isInstall($params['mall_id'], $params['addons_name']);
  341. $data['total_commission'] = 0;
  342. $data['is_install'] = 0;
  343. $basic = \Yii::$app->services->setting->addons->get($params['mall_id'], $params['addons_name'], 'basic');
  344. $data['is_show_at_center'] = 1;
  345. if(isset($basic['is_show_at_center'])) $data['is_show_at_center'] = $basic['is_show_at_center'];
  346. if ($is_install) {
  347. $model = self::findOne(['user_id' => $params['user_id'],'status'=>[StatusEnum::DISABLED,StatusEnum::ENABLED]]);
  348. $data['total_commission'] = $model['total_commission'] ?? 0;
  349. $data['is_install'] = $is_install;
  350. }
  351. return $data;
  352. }
  353. public static function getDistributionList($is_self_buy, $mall_id, $user_id)
  354. {
  355. $parent_id_arr = UserPartitionRelationship::getParentIdArr($user_id);
  356. $deep = ($is_self_buy == 1) ? 2 : 3;
  357. $new_parent_id_arr = [];
  358. for ($i = 0; $i < $deep; $i++) {
  359. $new_parent_id_arr[] = array_pop($parent_id_arr);
  360. }
  361. $where = ['user_id' => $new_parent_id_arr, 'mall_id' => $mall_id, 'status' => StatusEnum::ENABLED];
  362. $addons_distribution_list = Distribution::find()->where($where)->indexBy('user_id')->all();//查询分销商列表
  363. $distribution_list = [];
  364. foreach ($new_parent_id_arr as $k => $parent_id) {
  365. $distribution_list[$k] = [];
  366. if (!empty($addons_distribution_list[$parent_id])) $distribution_list[$k] = $addons_distribution_list[$parent_id];//按照关系排序
  367. }
  368. if ($is_self_buy) {
  369. $distribution = Distribution::findOne(['user_id' => $user_id]);
  370. if ($distribution) array_unshift($distribution_list, $distribution);
  371. }
  372. return $distribution_list;
  373. }
  374. public static function distributionInfo($user, $mall_id)
  375. {
  376. $configs = \Yii::$app->services->setting->addons->get($mall_id, AddonsEnum::ADDONS_NAME_DISTRIBUTION, 'basic');
  377. $distribution = Distribution::getOne([['user_id' => $user['id']], ['status' => StatusEnum::ENABLED], ['mall_id' => $mall_id]], true, ['distributionLevel']);
  378. if (empty($configs['is_apply'])) {
  379. //无条件
  380. if (empty($distribution)) {
  381. if(!isset($configs['is_default_level'])||!empty($configs['is_default_level'])) {
  382. $params['user_id'] = $user['id'];
  383. $params['mall_id'] = $mall_id;
  384. $params['status'] = StatusEnum::ENABLED;
  385. $distribution = Distribution::setData($params);
  386. }
  387. }
  388. }
  389. $data = [];
  390. $data['user_id'] = $user['id'];
  391. $data['nickname'] = empty($user->nickname) ? '' : $user->nickname;
  392. $data['avatar_url'] = empty($user->avatar_url) ? '' : $user->avatar_url;
  393. if (empty($distribution)) {
  394. $res = DistributionApply::getOne([['user_id' => $user['id']], ['status' => StatusEnum::ENABLED], ['mall_id' => $mall_id]], true, [], 'id desc');
  395. $setting = \Yii::$app->services->setting->addons->get($mall_id, DistributionEnum::ADDONS_NAME, 'basic');
  396. if (!empty($res)) {
  397. if ($res['check_status'] == 0) {
  398. $data['msg'] = '您已经申请了,请等待审核';
  399. $data['result'] = ['is_apply' => 2, 'msg' => '您已经申请了,请等待审核', 'is_distribution' => 0];
  400. return $data;
  401. }
  402. if ($res['check_status'] == 2) {
  403. $data['msg'] = $res['check_remark'];
  404. $data['result'] = ['is_apply' => 3, 'protocol' => $setting['protocol'], 'msg' => $res['check_remark'], 'is_distribution' => 0];
  405. }
  406. return $data;
  407. }
  408. $result = ['is_apply' => $setting['is_apply'], 'protocol' => $setting['protocol'], 'is_distribution' => 0];
  409. $data['msg'] = '您不是分销商';
  410. $data['result'] = $result;
  411. return $data;
  412. }
  413. $data['parent_name'] = '平台方';
  414. $data['parent_avatar_url'] = '';
  415. $data['parent_level_name'] = '';
  416. $parent_id = $user->parent_id ?? 0;
  417. if ($parent_id) {
  418. $parent = User::findOne($parent_id);
  419. $data['parent_name'] = $parent['nickname'] ?? '';
  420. $data['parent_avatar_url'] = $parent['avatar_url'] ?? '';
  421. $parent_distribution = Distribution::findOne(['user_id' => $parent_id]);
  422. $data['parent_level_name'] = $parent_distribution->distributionLevel->name ?? '默认等级';
  423. }
  424. $data['is_distribution'] = 0;
  425. $data['level_name'] = '';
  426. $data['frozen_price'] = 0;
  427. $data['total_price'] = 0;
  428. $data['total_income'] = 0;
  429. $data['yesterday_price'] = 0;
  430. if ($distribution) {
  431. $data['is_distribution'] = 1;
  432. $data['level_name'] = $configs['default_level_name'] ?? '默认等级';
  433. if(!empty($distribution['distributionLevel']['name'])){
  434. $data['level_name'] = $distribution['distributionLevel']['name'];
  435. }
  436. $wallet_type = 'commission';
  437. $yesterday = date('Y-m-d', strtotime('-1 day'));
  438. $start_time = "{$yesterday} 00:00:00";
  439. $end_time = "{$yesterday} 23:59:59";
  440. CapitalLog::$capitalType = "{$wallet_type}_frozen";
  441. $where = ['user_id' => $user['id'], 'from_type' => DistributionEnum::ADDONS_NAME, 'status' => CapitalLog::STATUS_WAIT_SEND];
  442. $query = CapitalLog::find();
  443. $frozen_price = $query->where($where)->sum('change_num');
  444. $yesterday_frozen_price = $query->where($where)
  445. ->andWhere(['<=', 'created_at', $end_time])
  446. ->andWhere(['>=', 'created_at', $start_time])
  447. ->sum('change_num');
  448. if (empty($yesterday_frozen_price)) $yesterday_frozen_price = 0;
  449. CapitalLog::$capitalType = "{$wallet_type}";
  450. $where = ['user_id' => $user['id'], 'from_type' => DistributionEnum::ADDONS_NAME];
  451. $query = CapitalLog::find();
  452. $total_price = $query->where($where)->sum('change_num');
  453. $yesterday_total_price = $query->where($where)
  454. ->andWhere(['<=', 'created_at', $end_time])
  455. ->andWhere(['>=', 'created_at', $start_time])
  456. ->sum('change_num');
  457. if (empty($yesterday_total_price)) $yesterday_total_price = 0;
  458. $data['total_price'] = empty($total_price) ? 0 : $total_price;
  459. $data['frozen_price'] = empty($frozen_price) ? 0 : $frozen_price;
  460. $data['total_income'] = bcadd($data['total_price'] , $data['frozen_price'],2);
  461. $data['yesterday_price'] = bcadd($yesterday_total_price , $yesterday_frozen_price,2);
  462. }
  463. $data['is_show_share_level'] = $configs['is_show_share_level'] ?? 0;
  464. $data['msg'] = '';
  465. return $data;
  466. }
  467. public static function getAddons(array $params){
  468. $is_install = MallAddons::isInstall($params['mall_id'], DistributionEnum::ADDONS_NAME);
  469. if($is_install){
  470. $detail = Addons::getOne([['name' => DistributionEnum::ADDONS_NAME], ['is_online' => 1]], true);
  471. return [
  472. 'addons_name'=>DistributionEnum::ADDONS_NAME,
  473. 'title'=>$detail['title'],
  474. ];
  475. }
  476. return [];
  477. }
  478. }