UserRechargeServices.php 18 KB

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