UserRechargeServices.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. declare (strict_types=1);
  12. namespace app\services\user;
  13. use app\dao\user\UserRechargeDao;
  14. use app\services\BaseServices;
  15. use app\services\pay\RechargeServices;
  16. use app\services\statistic\CapitalFlowServices;
  17. use app\services\system\config\SystemGroupDataServices;
  18. use crmeb\exceptions\AdminException;
  19. use crmeb\services\{
  20. FormBuilder as Form, MiniProgramService, WechatService
  21. };
  22. use think\exception\ValidateException;
  23. use think\facade\Route as Url;
  24. /**
  25. *
  26. * Class UserRechargeServices
  27. * @package app\services\user
  28. * @method be($map, string $field = '') 查询一条数据是否存在
  29. * @method getDistinctCount(array $where, $field, ?bool $search = true)
  30. * @method getTrendData($time, $type, $timeType)
  31. */
  32. class UserRechargeServices extends BaseServices
  33. {
  34. /**
  35. * UserRechargeServices constructor.
  36. * @param UserRechargeDao $dao
  37. */
  38. public function __construct(UserRechargeDao $dao)
  39. {
  40. $this->dao = $dao;
  41. }
  42. /**
  43. * 获取单条数据
  44. * @param int $id
  45. * @param array $field
  46. */
  47. public function getRecharge(int $id, array $field = [])
  48. {
  49. return $this->dao->get($id, $field);
  50. }
  51. /**
  52. * 获取统计数据
  53. * @param array $where
  54. * @param string $field
  55. * @return float
  56. */
  57. public function getRechargeSum(array $where, string $field = '')
  58. {
  59. $whereData = [];
  60. if (isset($where['data'])) {
  61. $whereData['time'] = $where['data'];
  62. }
  63. if (isset($where['paid']) && $where['paid'] != '') {
  64. $whereData['paid'] = $where['paid'];
  65. }
  66. if (isset($where['nickname']) && $where['nickname']) {
  67. $whereData['like'] = $where['nickname'];
  68. }
  69. if (isset($where['recharge_type']) && $where['recharge_type']) {
  70. $whereData['recharge_type'] = $where['recharge_type'];
  71. }
  72. return $this->dao->getWhereSumField($whereData, $field);
  73. }
  74. /**
  75. * 获取充值列表
  76. * @param array $where
  77. * @param string $field
  78. * @return array
  79. */
  80. public function getRechargeList(array $where, string $field = '*', $is_page = true)
  81. {
  82. $whereData = [];
  83. if (isset($where['data'])) {
  84. $whereData['time'] = $where['data'];
  85. }
  86. if (isset($where['paid']) && $where['paid'] != '') {
  87. $whereData['paid'] = $where['paid'];
  88. }
  89. if (isset($where['nickname']) && $where['nickname']) {
  90. $whereData['like'] = $where['nickname'];
  91. }
  92. [$page, $limit] = $this->getPageValue($is_page);
  93. $list = $this->dao->getList($whereData, $field, $page, $limit);
  94. $count = $this->dao->count($whereData);
  95. foreach ($list as &$item) {
  96. switch ($item['recharge_type']) {
  97. case 'routine':
  98. $item['_recharge_type'] = '小程序充值';
  99. break;
  100. case 'weixin':
  101. $item['_recharge_type'] = '公众号充值';
  102. break;
  103. default:
  104. $item['_recharge_type'] = '其他充值';
  105. break;
  106. }
  107. $item['_pay_time'] = $item['pay_time'] ? date('Y-m-d H:i:s', $item['pay_time']) : '暂无';
  108. $item['_add_time'] = $item['add_time'] ? date('Y-m-d H:i:s', $item['add_time']) : '暂无';
  109. $item['paid_type'] = $item['paid'] ? '已支付' : '未支付';
  110. unset($item['user']);
  111. }
  112. return compact('list', 'count');
  113. }
  114. /**
  115. * 获取用户充值数据
  116. * @return array
  117. */
  118. public function user_recharge(array $where)
  119. {
  120. $data = [];
  121. $data['sumPrice'] = $this->getRechargeSum($where, 'price');
  122. $data['sumRefundPrice'] = $this->getRechargeSum($where, 'refund_price');
  123. $where['recharge_type'] = 'routine';
  124. $data['sumRoutinePrice'] = $this->getRechargeSum($where, 'price');
  125. $where['recharge_type'] = 'weixin';
  126. $data['sumWeixinPrice'] = $this->getRechargeSum($where, 'price');
  127. return [
  128. [
  129. 'name' => '充值总金额',
  130. 'field' => '元',
  131. 'count' => $data['sumPrice'],
  132. 'className' => 'logo-yen',
  133. 'col' => 6,
  134. ],
  135. [
  136. 'name' => '充值退款金额',
  137. 'field' => '元',
  138. 'count' => $data['sumRefundPrice'],
  139. 'className' => 'logo-usd',
  140. 'col' => 6,
  141. ],
  142. [
  143. 'name' => '小程序充值金额',
  144. 'field' => '元',
  145. 'count' => $data['sumRoutinePrice'],
  146. 'className' => 'logo-bitcoin',
  147. 'col' => 6,
  148. ],
  149. [
  150. 'name' => '公众号充值金额',
  151. 'field' => '元',
  152. 'count' => $data['sumWeixinPrice'],
  153. 'className' => 'ios-bicycle',
  154. 'col' => 6,
  155. ],
  156. ];
  157. }
  158. /**退款表单
  159. * @param $id
  160. * @return mixed|void
  161. */
  162. public function refund_edit(int $id)
  163. {
  164. $UserRecharge = $this->getRecharge($id);
  165. if (!$UserRecharge) {
  166. throw new AdminException('数据不存在!');
  167. }
  168. if ($UserRecharge['paid'] != 1) {
  169. throw new AdminException('订单未支付');
  170. }
  171. if ($UserRecharge['price'] == $UserRecharge['refund_price']) {
  172. throw new AdminException('已退完支付金额!不能再退款了');
  173. }
  174. if ($UserRecharge['recharge_type'] == 'balance') {
  175. throw new AdminException('佣金转入余额,不能退款');
  176. }
  177. $f = array();
  178. $f[] = Form::input('order_id', '退款单号', $UserRecharge->getData('order_id'))->disabled(true);
  179. $f[] = Form::radio('refund_price', '状态', 1)->options([['label' => '本金(扣赠送余额)', 'value' => 1], ['label' => '仅本金', 'value' => 0]]);
  180. // $f[] = Form::number('refund_price', '退款金额', (float)$UserRecharge->getData('price'))->precision(2)->min(0)->max($UserRecharge->getData('price'));
  181. return create_form('编辑', $f, Url::buildUrl('/finance/recharge/' . $id), 'PUT');
  182. }
  183. /**
  184. * 退款操作
  185. * @param int $id
  186. * @param $refund_price
  187. * @return mixed
  188. */
  189. public function refund_update(int $id, string $refund_price)
  190. {
  191. $UserRecharge = $this->getRecharge($id);
  192. if (!$UserRecharge) {
  193. throw new AdminException('数据不存在!');
  194. }
  195. if ($UserRecharge['price'] == $UserRecharge['refund_price']) {
  196. throw new AdminException('已退完支付金额!不能再退款了');
  197. }
  198. if ($UserRecharge['recharge_type'] == 'balance') {
  199. throw new AdminException('佣金转入余额,不能退款');
  200. }
  201. $data['refund_price'] = $UserRecharge['price'];
  202. $refund_data['pay_price'] = $UserRecharge['price'];
  203. $refund_data['refund_price'] = $UserRecharge['price'];
  204. if ($refund_price == 1) {
  205. $number = bcadd($UserRecharge['price'], $UserRecharge['give_price'], 2);
  206. } else {
  207. $number = $UserRecharge['price'];
  208. }
  209. try {
  210. $recharge_type = $UserRecharge['recharge_type'];
  211. if ($recharge_type == 'weixin') {
  212. WechatService::payOrderRefund($UserRecharge['order_id'], $refund_data);
  213. } else {
  214. MiniProgramService::payOrderRefund($UserRecharge['order_id'], $refund_data);
  215. }
  216. } catch (\Exception $e) {
  217. throw new AdminException($e->getMessage());
  218. }
  219. if (!$this->dao->update($id, $data)) {
  220. throw new AdminException('修改提现数据失败');
  221. }
  222. //修改用户余额
  223. /** @var UserServices $userServices */
  224. $userServices = app()->make(UserServices::class);
  225. $userInfo = $userServices->getUserInfo($UserRecharge['uid']);
  226. if ($userInfo['now_money'] > $number) {
  227. $now_money = bcsub((string)$userInfo['now_money'], $number, 2);
  228. } else {
  229. $number = $userInfo['now_money'];
  230. $now_money = 0;
  231. }
  232. $userServices->update((int)$UserRecharge['uid'], ['now_money' => $now_money], 'uid');
  233. //写入资金流水
  234. /** @var CapitalFlowServices $capitalFlowServices */
  235. $capitalFlowServices = app()->make(CapitalFlowServices::class);
  236. $UserRecharge['nickname'] = $userInfo['nickname'];
  237. $UserRecharge['phone'] = $userInfo['phone'];
  238. $capitalFlowServices->setFlow($UserRecharge, 'refund_recharge');
  239. //保存余额记录
  240. /** @var UserMoneyServices $userMoneyServices */
  241. $userMoneyServices = app()->make(UserMoneyServices::class);
  242. $userMoneyServices->income('user_recharge_refund', $UserRecharge['uid'], $number, $now_money, $id);
  243. //提醒推送
  244. event('notice.notice', [['user_type' => strtolower($UserRecharge['recharge_type']), 'data' => $data, 'UserRecharge' => $UserRecharge, 'now_money' => $refund_price], 'recharge_order_refund_status']);
  245. return true;
  246. }
  247. /**
  248. * 删除
  249. * @param int $id
  250. * @return bool
  251. */
  252. public function delRecharge(int $id)
  253. {
  254. $rechargInfo = $this->getRecharge($id);
  255. if (!$rechargInfo) throw new AdminException('订单未找到');
  256. if ($rechargInfo->paid) {
  257. throw new AdminException('已支付的订单记录无法删除');
  258. }
  259. if ($this->dao->delete($id))
  260. return true;
  261. else
  262. throw new AdminException('删除失败');
  263. }
  264. /**
  265. * 生成充值订单号
  266. * @return bool|string
  267. */
  268. public function getOrderId()
  269. {
  270. return 'wx' . date('YmdHis', time()) . substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
  271. }
  272. /**
  273. * 导入佣金到余额
  274. * @param int $uid
  275. * @param $price
  276. * @return bool
  277. */
  278. public function importNowMoney(int $uid, $price)
  279. {
  280. /** @var UserServices $userServices */
  281. $userServices = app()->make(UserServices::class);
  282. $user = $userServices->getUserInfo($uid);
  283. if (!$user) {
  284. throw new ValidateException('数据不存在');
  285. }
  286. /** @var UserBrokerageServices $frozenPrices */
  287. $frozenPrices = app()->make(UserBrokerageServices::class);
  288. $broken_commission = $frozenPrices->getUserFrozenPrice($uid);
  289. $commissionCount = bcsub((string)$user['brokerage_price'], (string)$broken_commission, 2);
  290. if ($price > $commissionCount) {
  291. throw new ValidateException('转入金额不能大于可提现佣金!');
  292. }
  293. $edit_data = [];
  294. $edit_data['now_money'] = bcadd((string)$user['now_money'], (string)$price, 2);
  295. $edit_data['brokerage_price'] = $user['brokerage_price'] > $price ? bcsub((string)$user['brokerage_price'], (string)$price, 2) : 0;
  296. if (!$userServices->update($uid, $edit_data, 'uid')) {
  297. throw new ValidateException('修改用户信息失败');
  298. }
  299. //写入充值记录
  300. $rechargeInfo = [
  301. 'uid' => $uid,
  302. 'order_id' => $this->getOrderId(),
  303. 'recharge_type' => 'balance',
  304. 'price' => $price,
  305. 'give_price' => 0,
  306. 'paid' => 1,
  307. 'pay_time' => time(),
  308. 'add_time' => time()
  309. ];
  310. if (!$re = $this->dao->save($rechargeInfo)) {
  311. throw new ValidateException('写入余额充值失败');
  312. }
  313. //余额记录
  314. /** @var UserMoneyServices $userMoneyServices */
  315. $userMoneyServices = app()->make(UserMoneyServices::class);
  316. $userMoneyServices->income('brokerage_to_nowMoney', $uid, $price, $edit_data['now_money'], $re['id']);
  317. //写入提现记录
  318. $extractInfo = [
  319. 'uid' => $uid,
  320. 'real_name' => $user['nickname'],
  321. 'extract_type' => 'balance',
  322. 'extract_price' => $price,
  323. 'balance' => $user['brokerage_price'],
  324. 'add_time' => time(),
  325. 'status' => 1
  326. ];
  327. /** @var UserExtractServices $userExtract */
  328. $userExtract = app()->make(UserExtractServices::class);
  329. $userExtract->save($extractInfo);
  330. //佣金提现记录
  331. /** @var UserBrokerageServices $userBrokerageServices */
  332. $userBrokerageServices = app()->make(UserBrokerageServices::class);
  333. $userBrokerageServices->income('brokerage_to_nowMoney', $uid, $price, $edit_data['brokerage_price'], $re['id']);
  334. return true;
  335. }
  336. /**
  337. * 申请充值
  338. * @param int $uid
  339. * @return mixed
  340. */
  341. public function recharge(int $uid, $price, $recharId, $type, $from)
  342. {
  343. /** @var UserServices $userServices */
  344. $userServices = app()->make(UserServices::class);
  345. $user = $userServices->getUserInfo($uid);
  346. if (!$user) {
  347. throw new ValidateException('数据不存在');
  348. }
  349. switch ((int)$type) {
  350. case 0: //支付充值余额
  351. $paid_price = 0;
  352. if ($recharId) {
  353. /** @var SystemGroupDataServices $systemGroupData */
  354. $systemGroupData = app()->make(SystemGroupDataServices::class);
  355. $data = $systemGroupData->getDateValue($recharId);
  356. if ($data === false) {
  357. return app('json')->fail('您选择的充值方式已下架!');
  358. } else {
  359. $paid_price = $data['give_money'] ?? 0;
  360. }
  361. }
  362. $recharge_data = [];
  363. $recharge_data['order_id'] = $this->getOrderId();
  364. $recharge_data['uid'] = $uid;
  365. $recharge_data['price'] = $price;
  366. $recharge_data['recharge_type'] = $from;
  367. $recharge_data['paid'] = 0;
  368. $recharge_data['add_time'] = time();
  369. $recharge_data['give_price'] = $paid_price;
  370. $recharge_data['channel_type'] = $user['user_type'];
  371. if (!$rechargeOrder = $this->dao->save($recharge_data)) {
  372. throw new ValidateException('充值订单生成失败');
  373. }
  374. try {
  375. /** @var RechargeServices $recharge */
  376. $recharge = app()->make(RechargeServices::class);
  377. $order_info = $recharge->recharge((int)$rechargeOrder->id);
  378. } catch (\Exception $e) {
  379. throw new ValidateException($e->getMessage());
  380. }
  381. return ['msg' => '', 'type' => $from, 'data' => $order_info];
  382. case 1: //佣金转入余额
  383. $this->importNowMoney($uid, $price);
  384. return ['msg' => '转入余额成功', 'type' => $from, 'data' => []];
  385. default:
  386. throw new ValidateException('缺少参数');
  387. }
  388. }
  389. /**
  390. * //TODO用户充值成功后
  391. * @param $orderId
  392. */
  393. public function rechargeSuccess($orderId)
  394. {
  395. $order = $this->dao->getOne(['order_id' => $orderId, 'paid' => 0]);
  396. if (!$order) {
  397. throw new ValidateException('订单失效或者不存在');
  398. }
  399. /** @var UserServices $userServices */
  400. $userServices = app()->make(UserServices::class);
  401. $user = $userServices->getUserInfo((int)$order['uid']);
  402. if (!$user) {
  403. throw new ValidateException('数据不存在');
  404. }
  405. $price = bcadd((string)$order['price'], (string)$order['give_price'], 2);
  406. if (!$this->dao->update($order['id'], ['paid' => 1, 'pay_time' => time()], 'id')) {
  407. throw new ValidateException('修改订单失败');
  408. }
  409. $now_money = bcadd((string)$user['now_money'], (string)$price, 2);
  410. /** @var UserMoneyServices $userMoneyServices */
  411. $userMoneyServices = app()->make(UserMoneyServices::class);
  412. $userMoneyServices->income('user_recharge', $user['uid'], ['number' => $price, 'price' => $order['price'], 'give_price' => $order['give_price']], $now_money, $order['id']);
  413. if (!$userServices->update((int)$order['uid'], ['now_money' => $now_money], 'uid')) {
  414. throw new ValidateException('修改用户信息失败');
  415. }
  416. /** @var CapitalFlowServices $capitalFlowServices */
  417. $capitalFlowServices = app()->make(CapitalFlowServices::class);
  418. $order['nickname'] = $user['nickname'];
  419. $order['phone'] = $user['phone'];
  420. $capitalFlowServices->setFlow($order, 'recharge');
  421. //提醒推送
  422. event('notice.notice', [['order' => $order, 'now_money' => $now_money], 'recharge_success']);
  423. return true;
  424. }
  425. /**根据查询用户充值金额
  426. * @param array $where
  427. * @return float|int
  428. */
  429. public function getRechargeMoneyByWhere(array $where, string $rechargeSumField, string $selectType, string $group = "")
  430. {
  431. switch ($selectType) {
  432. case "sum" :
  433. return $this->dao->getWhereSumField($where, $rechargeSumField);
  434. case "group" :
  435. return $this->dao->getGroupField($where, $rechargeSumField, $group);
  436. }
  437. }
  438. }