ScoreController.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. <?php
  2. namespace api\modules\v1\controllers\user;
  3. use addons\PointUpperLimit\common\service\SettingService;
  4. use addons\PointUpperLimit\common\service\UserService;
  5. use api\controllers\OnAuthController;
  6. use common\enums\AddonsEnum;
  7. use common\enums\StatusEnum;
  8. use common\enums\UserWalletEnum;
  9. use common\helpers\BcHelper;
  10. use common\helpers\DateHelper;
  11. use common\helpers\LockHelper;
  12. use common\models\common\GlobalVarMap;
  13. use common\models\common\CapitalLog;
  14. use common\models\mall\MallAddons;
  15. use common\models\user\User;
  16. use common\models\common\ScoreLog;
  17. use common\models\user\UserPartitionRelationship;
  18. use common\models\user\UserWallet;
  19. use common\models\user\UserWithdrawLog;
  20. use services\common\UserWalletService;
  21. use Yii;
  22. use yii\db\Exception;
  23. class ScoreController extends OnAuthController
  24. {
  25. public $modelClass = '';
  26. /**
  27. *
  28. * 不用进行登录验证的方法
  29. *
  30. * 例如: ['index', 'update', 'create', 'view', 'delete']
  31. * 默认全部需要验证
  32. *
  33. * @var array
  34. */
  35. protected $authOptional = ['login', 'mobile-login', 'sms-code', 'register', 'up-pwd'];
  36. /**
  37. * 积分汇总
  38. * @return mixed|void
  39. */
  40. public function actionTotalData()
  41. {
  42. $user_wallet = UserWallet::findOne(['user_id' => $this->user_id]);
  43. $data['score'] = empty($user_wallet['score']) ? 0 : $user_wallet['score'];
  44. // 积分配置
  45. $setting = Yii::$app->services->setting->mall->get($this->mall_id, 'score');
  46. $data['is_score_transfer'] = $setting['is_score_transfer'];
  47. $data['is_score_balance'] = $setting['is_score_balance']; // 判断是否有等级限制
  48. $data['is_hide_score_details'] = $setting['is_hide_score_details'] ?? 0; // 前端隐藏结算明细是否开启
  49. // 判断是否有积分转余额权限
  50. if (!empty($data['is_score_balance']) && !empty($setting['level_limit_type']) && !empty($setting['level_limit_levels'])) {
  51. $user = User::findOne(['mall_id' => $this->mall_id, 'id' => $this->user_id]);
  52. $user_level = !empty($user) ? $user->level : 0;
  53. $level_limit_levels = json_decode($setting['level_limit_levels'], true);
  54. !in_array($user_level, $level_limit_levels) && $data['is_score_balance'] = 0;
  55. }
  56. // 待返积分
  57. $data['wait_return_score'] = 0;
  58. if (MallAddons::isInstall($this->mall_id, AddonsEnum::ADDONS_NAME_POINT_UPPER_LIMIT)) {
  59. if (!empty((new SettingService())->isEnable($this->mall_id))) { // 取出用户待返积分
  60. try {
  61. $data['wait_return_score'] = (new UserService())->getUserQuota($this->mall_id, $this->user_id, false);
  62. } catch (\Exception $e) {
  63. return $this->error($e->getMessage());
  64. }
  65. }
  66. }
  67. CapitalLog::$capitalType = 'score';
  68. //获取用户累计增值金额
  69. $total_added_num = CapitalLog::find()->where(['mall_id' => $this->mall_id, 'user_id' => $this->user_id, 'from_type' => 'ScoreGame', 'capital_type' => 'score_game_increment'])->sum('change_num');
  70. $yesterDay = DateHelper::yesterDay();
  71. $yesteday_added_num = CapitalLog::find()
  72. ->where(['mall_id' => $this->mall_id, 'user_id' => $this->user_id, 'from_type' => 'ScoreGame', 'capital_type' => 'score_game_increment'])
  73. ->andWhere(['>=', 'created_at', $yesterDay['start']])
  74. ->andWhere(['<=', 'created_at', $yesterDay['end']])
  75. ->sum('change_num');
  76. $data['total_added_num'] = $total_added_num ?? 0; //总增值
  77. $data['yesteday_added_num'] = $yesteday_added_num ?? 0; //昨日增值
  78. $data['is_score_cash'] = $setting['score_cash_status'] ?? 0;
  79. $this->success('操作成功', $data);
  80. }
  81. /**
  82. * 余额充值/消费/提现记录
  83. * @return mixed|void
  84. */
  85. public function actionListOld()
  86. {
  87. $params = \Yii::$app->request->get();
  88. $where = [];
  89. $where[] = ['mall_id' => $this->mall_id];
  90. $where[] = ['user_id' => $this->user_id];
  91. $params['select'] = 'id,change_type,change_num,current_num,desc,created_at,from_type,capital_type';
  92. $params['order'] = 'id desc';
  93. $params['where'] = $where;
  94. $list = ScoreLog::listPage($params);
  95. $list['from_type_map'] = UserWalletEnum::getFromTypeMapByScore();
  96. $list['capital_type_map'] = UserWalletEnum::getCapitalTypeMapByScore();
  97. return $this->success('操作成功', $list);
  98. }
  99. public function actionList()
  100. {
  101. $params = \Yii::$app->request->get();
  102. CapitalLog::$capitalType = 'score';
  103. $status = $params['status']??1;
  104. $where = [];
  105. if ($status == 0) {
  106. CapitalLog::$capitalType = 'score_frozen';
  107. $where[] = ['status'=>$status];
  108. }
  109. $where[] = ['mall_id' => $this->mall_id];
  110. $where[] = ['user_id' => $this->user_id];
  111. $params['select'] = 'id,change_type,change_num,current_num,desc,created_at,from_type,capital_type';
  112. $params['order'] = 'id desc';
  113. $params['where'] = $where;
  114. $params['page'] = empty($get['page']) ? 1 : $get['page'];
  115. $list = CapitalLog::listPage($params, false);
  116. $list['from_type_map'] = GlobalVarMap::getEnumMapByType('FromTypeMap', $this->mall_id);
  117. foreach ($list['from_type_map'] as $key => $item) {
  118. if ($key == 'ScoreBonus') {
  119. $mall_config = Yii::$app->services->setting->mall->get($this->mall_id, 'score');
  120. $list['from_type_map'][$key] = !empty($mall_config['score_name']) ? $mall_config['score_name'] . '分红' : '积分分红';
  121. }
  122. }
  123. $list['capital_type_map'] = GlobalVarMap::getEnumMapByType('CapitalTypeMap', $this->mall_id);
  124. // $list['from_type_map'] = UserWalletEnum::getFromTypeMapByScore();
  125. // $list['capital_type_map'] = UserWalletEnum::getCapitalTypeMapByScore();
  126. if(!empty($list)){
  127. $score_name = \Yii::$app->services->setting->mall->get($this->mall_id, 'score.score_name');
  128. $balance_name = \Yii::$app->services->setting->mall->get($this->mall_id, 'balance.balance_name');
  129. foreach ($list['capital_type_map'] as &$val){
  130. $val = str_replace('积分',$score_name,$val);
  131. $val = str_replace('余额',$balance_name,$val);
  132. }
  133. foreach ($list['list'] as &$item){
  134. $item['desc'] = str_replace('积分',$score_name,$item['desc']);
  135. $item['desc'] = str_replace('金额',$score_name,$item['desc']);
  136. }
  137. }
  138. if ($params['page'] == 1) {
  139. $setting = \Yii::$app->services->setting->mall->get($this->mall_id, 'score');
  140. $list['tab_alias'] = [
  141. 'wait_settlement' => !empty($setting['wait_settlement']) ? $setting['wait_settlement'] : '未结算',
  142. 'finish_settlement' => !empty($setting['finish_settlement']) ? $setting['finish_settlement'] : '已结算',
  143. ];
  144. }
  145. return $this->success('操作成功', $list);
  146. }
  147. /**
  148. * 积分转送/转入页面
  149. * @Author: lun
  150. * @DateTime: 2021/11/24 0024 11:04
  151. * @Copyright: copyright (c) 2021 广东七件事集团
  152. * @return mixed|void
  153. */
  154. public function actionTransfer()
  155. {
  156. $form = Yii::$app->request->get();
  157. $rules = [[['type'], 'required'], [['type'], 'in', 'range' => ['score', 'balance']]];
  158. $res = Yii::$app->services->validate->validate($form, $rules);
  159. if ($res === false) return $this->error(Yii::$app->services->validate->getErrorMessage());
  160. // 查询用户积分余额
  161. $score = UserWallet::find()->select('score')->where(['mall_id'=>$this->mall_id,'user_id'=>$this->user_id,'status'=>StatusEnum::ENABLED])->scalar();
  162. // 获取转送配置
  163. $config = Yii::$app->services->setting->mall->get($this->mall_id, 'score');
  164. if ($form['type'] == 'score') {
  165. $ratio = $config['transfer_poundage'];
  166. $explain = "转送手续费:{$ratio}%";
  167. } elseif ($form['type'] == 'balance') {
  168. $balance_name = Yii::$app->services->setting->mall->get($this->mall_id, 'balance.balance_name');
  169. $ratio = $config['score_balance_ratio'];
  170. $explain = "{$ratio}{$config['score_name']}转换1{$balance_name}";
  171. if(!empty($config['score_balance_poundage'])){
  172. $explain .= ",手续费:{$config['score_balance_poundage']}%";
  173. }
  174. }
  175. $pay_password_status = $config['enable_password'] ?? 0;
  176. $transaction_password = User::find()->select('transaction_password')->where(['mall_id'=>$this->mall_id,'id'=>$this->user_id,'status'=>StatusEnum::ENABLED])->scalar();
  177. $is_transaction_password = empty(trim($transaction_password)) ? false : true;
  178. $data = ['capital' => $score, 'explain' => $explain, 'ratio' => $ratio];
  179. $data = array_merge($data, compact('pay_password_status', 'is_transaction_password'));
  180. return $this->success('操作成功', $data);
  181. }
  182. /**
  183. * 积分转送提交
  184. * @Author: lun
  185. * @DateTime: 2021/11/24 0024 11:08
  186. * @Copyright: copyright (c) 2021 广东七件事集团
  187. * @return mixed|void
  188. */
  189. public function actionTransferScore()
  190. {
  191. if (Yii::$app->request->isPost) {
  192. $form = Yii::$app->request->post();
  193. $rules = [
  194. [['score','user_id'], 'required'],
  195. [['score','user_id'], 'integer'],
  196. [['score'], 'compare', 'compareValue' => 0, 'operator' => '>'],
  197. [['transaction_password'], 'string'],
  198. ];
  199. $res = Yii::$app->services->validate->validate($form, $rules);
  200. if ($res === false) return $this->error(Yii::$app->services->validate->getErrorMessage());
  201. $key = sprintf('TransferScore:%s', $this->user_id);
  202. try {
  203. if (LockHelper::fLock($key)) throw new Exception('请勿频繁请求');
  204. // 检测转送用户是否是本人
  205. if ($form['user_id'] == $this->user_id) throw new Exception('赠送的用户不能是本人哦');
  206. // 检查用户是否存在
  207. $receive_user = User::getUser([['id' => $form['user_id']]], 'id');
  208. if (empty($receive_user)) throw new Exception('赠送的用户不存在');
  209. // 获取配置
  210. $config = Yii::$app->services->setting->mall->get($this->mall_id, 'score');
  211. if (empty($config['is_score_transfer'])) throw new Exception('积分转增功能尚未开启');
  212. $check_password_result = UserWithdrawLog::checkPassword($this->user_id, $form['transaction_password'], $config);
  213. if(is_array($check_password_result)){
  214. throw new Exception($check_password_result['msg']);
  215. }
  216. if (!empty($config['source_transfer_permission'])) {
  217. // $parent_ids = UserRelationship::getParentIdArr($this->user_id);// 获取上级
  218. $parent_ids = UserPartitionRelationship::getParentIdArr($this->user_id);// 获取上级
  219. // $child_ids = UserRelationship::getChildIdArr($this->user_id);// 获取下级
  220. $child_ids = UserPartitionRelationship::getChildIdArr($this->user_id);// 获取下级
  221. if (!in_array($receive_user->id, array_merge($parent_ids, $child_ids))) throw new Exception('转送会员不在你的团队中');
  222. }
  223. $fee = bcdiv($form['score'] * $config['transfer_poundage'], 100, 2);// 手续费
  224. $sub_score = bcadd($form['score'], $fee, 2);// 最终扣减积分额度
  225. // 查询用户积分余额
  226. $user_wallet = UserWallet::find()->select('id,score')->where(['mall_id'=>$this->mall_id,'user_id'=>$this->user_id,'status'=>StatusEnum::ENABLED])->asArray()->one();
  227. if (empty($user_wallet) || ($user_wallet['score'] < $sub_score)) throw new Exception('积分额度不足');
  228. // 组合用户
  229. $list = [['user_id'=>$this->user_id,'type' => 'sub'], ['user_id'=>$receive_user->id,'type'=>'add']];
  230. $give_user = $this->user_id;// 转出用户
  231. $receive_user = '用户ID:'.$receive_user->id;// 接收用户
  232. $fee_str = $fee <= 0 ? '' : ',手续费'.$fee;
  233. // 循环生成数据
  234. foreach ($list as $item) {
  235. $insert_wallet[] = [
  236. 'mall_id' => $this->mall_id,
  237. 'user_id' => $item['user_id'],
  238. 'is_frozen' => false,
  239. 'wallet_type' => UserWalletService::WALLET_TYPE_SCORE,
  240. 'money' => $item['type'] == 'sub' ? -$sub_score : $form['score'],
  241. 'desc' => $item['type'] == 'sub' ? '积分转给'.$receive_user.$fee_str : '用户ID'.$give_user.'积分转入',
  242. 'source_table' => UserWallet::tableName(),
  243. 'source_table_id' => $user_wallet['id'],
  244. 'from_type' => UserWalletEnum::TRANSFER,
  245. 'capital_type'=> UserWalletEnum::TRANSFER_GIVE
  246. ];
  247. }
  248. // 异步处理积分
  249. if ($insert_wallet) {
  250. $res = UserWalletService::batchHandleByQueue($insert_wallet);
  251. if (empty($res)) throw new Exception(UserWalletService::getStaticError());
  252. }
  253. LockHelper::unFLock($key);
  254. $this->success('转送成功');
  255. } catch (Exception $e) {
  256. LockHelper::unFLock($key);
  257. return $this->error('赠送失败:' . $e->getMessage());
  258. }
  259. }
  260. }
  261. /**
  262. * 积分转入余额
  263. * @Author: lun
  264. * @DateTime: 2021/11/24 0024 14:58
  265. * @Copyright: copyright (c) 2021 广东七件事集团
  266. * @return mixed|void
  267. * @throws \Exception
  268. */
  269. public function actionTransferBalance()
  270. {
  271. if (Yii::$app->request->isPost) {
  272. $form = Yii::$app->request->post();
  273. $rules = [
  274. [['score'], 'required'],
  275. [['score'], 'integer'],
  276. [['score'], 'compare', 'compareValue' => 0, 'operator' => '>'],
  277. [['transaction_password'], 'string'],
  278. ];
  279. $res = Yii::$app->services->validate->validate($form, $rules);
  280. if ($res === false) return $this->error(Yii::$app->services->validate->getErrorMessage());
  281. $key = sprintf('TransferBalance:%s', $this->user_id);
  282. try {
  283. if (LockHelper::fLock($key)) throw new Exception('请勿频繁请求');
  284. // 获取配置
  285. $config = Yii::$app->services->setting->mall->get($this->mall_id, 'score');
  286. if (empty($config['is_score_balance'])) throw new Exception('积分转余额功能尚未开启');
  287. if (empty($config['score_balance_ratio'])) throw new Exception('积分转余额功能尚未开启');
  288. // 判断是否有积分转余额权限
  289. if (!empty($config['level_limit_type']) && !empty($config['level_limit_levels'])) {
  290. $user = User::findOne(['mall_id' => $this->mall_id, 'id' => $this->user_id]);
  291. $user_level = !empty($user) ? $user->level : 0;
  292. $level_limit_levels = json_decode($config['level_limit_levels'], true);
  293. if(!in_array($user_level, $level_limit_levels)) throw new Exception('您暂无积分转余额权限');;
  294. }
  295. $check_password_result = UserWithdrawLog::checkPassword($this->user_id, $form['transaction_password'], $config);
  296. if(is_array($check_password_result)){
  297. throw new Exception($check_password_result['msg']);
  298. }
  299. $balance = BcHelper::floorFloat(($form['score']/$config['score_balance_ratio']),2);// 保留两位小数,向下取整
  300. //是否设置手续费
  301. $poundage = 0;
  302. if(!empty($config['score_balance_poundage'])){
  303. $poundage = BcHelper::floorFloat(($balance * $config['score_balance_poundage'] / 100),2);
  304. $balance = bcsub($balance,$poundage,2);
  305. }
  306. // 查询用户积分余额
  307. $user_wallet = UserWallet::find()->select('id,score')->where(['mall_id'=>$this->mall_id,'user_id'=>$this->user_id,'status'=>StatusEnum::ENABLED])->asArray()->one();
  308. if (empty($user_wallet) || ($user_wallet['score'] < $form['score'])) throw new Exception('积分额度不足');
  309. // 扣减积分
  310. $insert_wallet[] = [
  311. 'mall_id' => $this->mall_id,
  312. 'user_id' => $this->user_id,
  313. 'is_frozen' => false,
  314. 'wallet_type' => UserWalletService::WALLET_TYPE_SCORE,
  315. 'money' => -$form['score'],
  316. 'desc' => '积分转入余额',
  317. 'source_table' => UserWallet::tableName(),
  318. 'source_table_id' => $user_wallet['id'],
  319. 'from_type' => UserWalletEnum::TRANSFER,
  320. 'capital_type'=> UserWalletEnum::TRANSFER_BALANCE
  321. ];
  322. // 增加余额
  323. $desc = '积分转入余额';
  324. if($poundage > 0){
  325. $desc .= ',手续费扣除:'.$poundage;
  326. }
  327. $insert_wallet[] = [
  328. 'mall_id' => $this->mall_id,
  329. 'user_id' => $this->user_id,
  330. 'is_frozen' => false,
  331. 'wallet_type' => UserWalletService::WALLET_TYPE_BALANCE,
  332. 'money' => $balance,
  333. 'desc' => $desc,
  334. 'source_table' => UserWallet::tableName(),
  335. 'source_table_id' => $user_wallet['id'],
  336. 'from_type' => UserWalletEnum::RECHARGE,
  337. 'capital_type'=> UserWalletEnum::RECHARGE_SCORE
  338. ];
  339. // 异步处理积分
  340. if ($insert_wallet) {
  341. $res = UserWalletService::batchHandleByQueue($insert_wallet);
  342. if (empty($res)) throw new Exception(UserWalletService::getStaticError());
  343. }
  344. LockHelper::unFLock($key);
  345. $this->success('转入成功');
  346. } catch (Exception $e) {
  347. LockHelper::unFLock($key);
  348. return $this->error('转入失败:' . $e->getMessage());
  349. }
  350. }
  351. }
  352. public function actionWithdrawList()
  353. {
  354. if (!Yii::$app->request->isGet) {
  355. return $this->error('请求方式非法');
  356. }
  357. $where[] = ['mall_id' => $this->mall_id];
  358. $where[] = ['user_id' => $this->user_id];
  359. $where[] = ['from' => UserWithdrawLog::FROM_SCORE];
  360. $where[]=['!=','status',-1];
  361. $params['where'] = $where;
  362. $params['select'] = 'id,order_no,num,actual_num,poundage_num,poundage_ratio,status,type,created_at';
  363. $params['order'] = 'id desc';
  364. $list = UserWithdrawLog::listPage($params);
  365. if($list && $list['list']){
  366. $ids = array_column($list['list'],'id');
  367. if ($this->platform == 'mp-wx') {
  368. $mini_program = Yii::$app->services->setting->mall->get($this->mall_id, 'mini_program', true);
  369. $appId = $mini_program['app_id'] ?? '';
  370. } else {
  371. $wechat_conf = Yii::$app->services->setting->mall->get($this->mall_id, 'wechat', true);
  372. $appId = $wechat_conf['app_id'] ?? '';
  373. }
  374. $status_msg = UserWithdrawLog::$status_msg;
  375. //查询对应的积分记录
  376. $log_list = ScoreLog::find()->where(['source_table' => 'user_wallet','source_table_id' => $ids])->indexBy('source_table_id')->asArray()->all();
  377. $wechat_transfer_log_list = \common\models\wechat\WechatTransferLog::lists(['where' => [['cash_id' => $ids]], 'index' => 'cash_id']);
  378. $list['list'] = array_map(function($item) use ($log_list,$status_msg,$appId,$wechat_transfer_log_list) {
  379. $v['transfer_result'] = [];
  380. if (isset($wechat_transfer_log_list[$item['id']])) {
  381. $payment_conf = \Yii::$app->services->setting->mall->get($this->mall_id, 'pay.wechat', true);
  382. $payment_conf = json_decode($payment_conf, true);
  383. $mchId = $payment_conf['wechat_mch_id'] ?? '';
  384. $wechat_transfer = $wechat_transfer_log_list[$item['id']];
  385. $transfer_result = json_decode($wechat_transfer['transfer_result'], true);
  386. $transfer_result['mchId'] = $mchId;
  387. $transfer_result['appId'] = $appId;
  388. $item['transfer_result'] = $transfer_result;
  389. }
  390. $log = $log_list[$item['id']] ?? [];
  391. $log['change_num'] = $log['change_num'] ?? 0;
  392. $item['desc'] = '提现'.$log['change_num'].'商城积分';
  393. $item['created_at'] = date("Y-m-d H:i:s",$item["created_at"]);
  394. $item['change_num'] = $item['num'];
  395. $item['status_text'] = $status_msg[$item['status']] ?? '';
  396. return $item;
  397. },$list['list']);
  398. }
  399. return $this->success('操作成功', $list);
  400. }
  401. }