BalanceLogService.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
  4. // +----------------------------------------------------------------------
  5. // | 版权所有 2017~2021 LARAVEL研发中心
  6. // +----------------------------------------------------------------------
  7. // | 官方网站: http://www.laravel.cn
  8. // +----------------------------------------------------------------------
  9. // | Author: laravel开发员 <laravel.qq.com>
  10. // +----------------------------------------------------------------------
  11. namespace App\Services\Common;
  12. use App\Models\AccountLogModel;
  13. use App\Models\ActionLogModel;
  14. use App\Models\BalanceLogModel;
  15. use App\Models\DriverModel;
  16. use App\Models\FreightPackageModel;
  17. use App\Models\MemberModel;
  18. use App\Services\Api\MessageService;
  19. use App\Services\Api\PaymentService;
  20. use App\Services\BaseService;
  21. use App\Services\RedisService;
  22. use Illuminate\Support\Facades\DB;
  23. /**
  24. * 余额账户管理-服务类
  25. * @author laravel开发员
  26. * @since 2020/11/11
  27. * Class BalanceLogService
  28. * @package App\Services\Common
  29. */
  30. class BalanceLogService extends BaseService
  31. {
  32. // 静态对象
  33. protected static $instance = null;
  34. /**
  35. * 构造函数
  36. * @author laravel开发员
  37. * @since 2020/11/11
  38. */
  39. public function __construct()
  40. {
  41. $this->model = new BalanceLogModel();
  42. }
  43. /**
  44. * 静态入口
  45. */
  46. public static function make()
  47. {
  48. if (!self::$instance) {
  49. self::$instance = new static();
  50. }
  51. return self::$instance;
  52. }
  53. /**
  54. * 列表
  55. * @param $params
  56. * @param int $pageSize
  57. * @return array
  58. */
  59. public function getDataList($params, $pageSize = 10)
  60. {
  61. $where = ['a.mark' => 1];
  62. $list = $this->model->from('balance_logs as a')
  63. ->leftJoin('member as b','b.id','=','a.user_id')
  64. ->leftJoin('driver as c','c.id','=','a.user_id')
  65. ->where($where)
  66. ->where(function ($query) use($params){
  67. $userType = isset($params['user_type'])? $params['user_type'] : 0;
  68. if($userType == 1){
  69. $query->where('a.user_type', $userType);
  70. $keyword = isset($params['keyword'])? $params['keyword'] : '';
  71. if($keyword){
  72. $query->where(function($query) use($keyword){
  73. $query->where('a.order_no','like',"%{$keyword}%")->orWhere('b.nickname','like',"%{$keyword}%")->orWhere('b.mobile','like',"%{$keyword}%");
  74. });
  75. }
  76. }else if ($userType == 2){
  77. $query->where('a.user_type', $userType);
  78. $keyword = isset($params['keyword'])? $params['keyword'] : '';
  79. if($keyword){
  80. $query->where(function($query) use($keyword){
  81. $query->where('a.order_no','like',"%{$keyword}%")->orWhere('c.realname','like',"%{$keyword}%")->orWhere('c.mobile','like',"%{$keyword}%");
  82. });
  83. }
  84. }
  85. })
  86. ->where(function ($query) use($params){
  87. $status = isset($params['status'])? $params['status'] : 0;
  88. if($status>0 && is_array($status)){
  89. $query->whereIn('a.status', $status);
  90. }else if($status){
  91. $query->where('a.status', $status);
  92. }
  93. $type = isset($params['type'])? $params['type'] : 0;
  94. if($type>0){
  95. $query->where('a.type', $type);
  96. }
  97. })
  98. ->select(['a.*','b.nickname as user_nickname','b.realname as user_realname','b.mobile as user_mobile','c.realname as driver_name','c.mobile as driver_mobile','c.realname as driver_realname'])
  99. ->orderBy('a.create_time','desc')
  100. ->orderBy('a.id','desc')
  101. ->paginate($pageSize > 0 ? $pageSize : 9999999);
  102. $list = $list? $list->toArray() :[];
  103. if($list){
  104. foreach($list['data'] as &$item){
  105. $item['create_time'] = $item['create_time']? datetime($item['create_time'],'Y-m-d H.i.s') : '';
  106. $item['qrcode'] = $item['qrcode']? get_image_url($item['qrcode']) : '';
  107. $item['account'] = $item['account']? json_decode($item['account'], true) : [];
  108. $item['username'] = $item['user_nickname']? $item['user_nickname'].($item['user_mobile']?'-'.$item['user_mobile']:'') : '';
  109. $item['driver'] = $item['driver_name']? $item['driver_name'].($item['driver_mobile']?'-'.$item['driver_mobile']:'') : '';
  110. if($item['user_type'] == 2){
  111. $item['realname'] = $item['realname']? $item['realname'] : $item['driver_realname'];
  112. }else{
  113. $item['realname'] = $item['realname']? $item['realname'] : $item['user_realname'];
  114. }
  115. }
  116. }
  117. return [
  118. 'pageSize'=> $pageSize,
  119. 'total'=>isset($list['total'])? $list['total'] : 0,
  120. 'list'=> isset($list['data'])? $list['data'] : []
  121. ];
  122. }
  123. /**
  124. * 统计
  125. * @param $params
  126. * @return array
  127. */
  128. public function getCount($params)
  129. {
  130. $where = ['a.mark' => 1];
  131. $model = $this->model->from('balance_logs as a')
  132. ->leftJoin('member as b','b.id','=','a.user_id')
  133. ->leftJoin('driver as c','c.id','=','a.user_id')
  134. ->where($where)
  135. ->where(function ($query) use($params){
  136. $userType = isset($params['user_type'])? $params['user_type'] : 0;
  137. if($userType == 1){
  138. $query->where('a.user_type', $userType);
  139. $keyword = isset($params['keyword'])? $params['keyword'] : '';
  140. if($keyword){
  141. $query->where(function($query) use($keyword){
  142. $query->where('a.order_no','like',"%{$keyword}%")->orWhere('b.nickname','like',"%{$keyword}%")->orWhere('b.mobile','like',"%{$keyword}%");
  143. });
  144. }
  145. }else if ($userType == 2){
  146. $query->where('a.user_type', $userType);
  147. $keyword = isset($params['keyword'])? $params['keyword'] : '';
  148. if($keyword){
  149. $query->where(function($query) use($keyword){
  150. $query->where('a.order_no','like',"%{$keyword}%")->orWhere('c.realname','like',"%{$keyword}%")->orWhere('c.mobile','like',"%{$keyword}%");
  151. });
  152. }
  153. }
  154. })
  155. ->where(function ($query) use($params){
  156. $status = isset($params['status'])? $params['status'] : 0;
  157. if($status>0 && is_array($status)){
  158. $query->whereIn('a.status', $status);
  159. }else if($status){
  160. $query->where('a.status', $status);
  161. }
  162. $type = isset($params['type'])? $params['type'] : 0;
  163. if($type>0){
  164. $query->where('a.type', $type);
  165. }
  166. });
  167. $counts = [
  168. 'count'=> $model->count('a.id'),
  169. 'total'=> $model->sum('a.money'),
  170. ];
  171. return $counts;
  172. }
  173. /**
  174. * 统计用户充值/提现金额
  175. * @param int $status
  176. * @param int $type 类型:1-充值,2-提现
  177. * @return mixed
  178. */
  179. public function getTotalByStatus($userType=1,$status=2, $type=2)
  180. {
  181. $where = ['mark' => 1];
  182. return $this->model->where($where)->where(function($query) use($userType,$type,$status){
  183. if($userType){
  184. $query->where('user_type',$userType);
  185. }
  186. if($status){
  187. $query->where('status',$status);
  188. }
  189. if($type){
  190. $query->where('type',$type);
  191. }
  192. })->sum('money');
  193. }
  194. /**
  195. * 统计用户提现数量
  196. * @param int $userType 用户类型:1-用户,2-司机
  197. * @return mixed
  198. */
  199. public function getCountByType($userType=1)
  200. {
  201. $where = ['mark' => 1,'status'=>2];
  202. return $this->model->where($where)->where(function($query) use($userType){
  203. if($userType){
  204. $query->where('user_type',$userType);
  205. }
  206. })->count('user_id');
  207. }
  208. /**
  209. * 编辑
  210. * @return array
  211. */
  212. public function edit()
  213. {
  214. $params = request()->post();
  215. $id = isset($params['id'])? $params['id'] : 0;
  216. $data = [
  217. 'id'=> $id,
  218. 'actual_money'=> isset($params['actual_money'])? floatval($params['actual_money']) : 0,
  219. 'audit_remark'=> isset($params['audit_remark'])? trim($params['audit_remark']) : '',
  220. 'status'=> isset($params['status'])? $params['status'] : 0,
  221. 'update_time'=> time(),
  222. ];
  223. if($data['status'] == 2){
  224. $data['pay_status'] = 20;
  225. }
  226. if($data['actual_money']<=0){
  227. $data['actual_money'] = isset($params['money'])? floatval($params['money']) : 0;
  228. }
  229. return parent::edit($data);
  230. }
  231. /**
  232. * 审核
  233. * @return array
  234. */
  235. public function auth()
  236. {
  237. $params = request()->post();
  238. $id = isset($params['id'])? $params['id'] : 0;
  239. $paStatus = isset($params['pay_status'])? $params['pay_status'] : 10;
  240. $cacheKey = "caches:members:withdraw:auth_lock_{$id}";
  241. if(RedisService::get($cacheKey)){
  242. return message('请不要频繁操作',false);
  243. }
  244. $data = [
  245. 'id'=> $id,
  246. 'actual_money'=> isset($params['actual_money'])? floatval($params['actual_money']) : 0,
  247. 'audit_remark'=> isset($params['audit_remark'])? trim($params['audit_remark']) : '',
  248. 'status'=> isset($params['status'])? $params['status'] : 0,
  249. 'update_time'=> time(),
  250. ];
  251. if($data['actual_money']<=0){
  252. $data['actual_money'] = isset($params['money'])? floatval($params['money']) : 0;
  253. }
  254. $info = $this->model->with(['member','driver'])->where(['id'=> $id,'mark'=>1])->first();
  255. if($id<=0 || empty($info)){
  256. return message('提现记录不存在',false);
  257. }
  258. $status = isset($info['status'])? $info['status'] : 0;
  259. if($status != 1){
  260. return message('当前状态不可操作',false);
  261. }
  262. $data['pay_status'] = $paStatus;
  263. // 处理
  264. RedisService::set($cacheKey, $info, rand(2,3));
  265. DB::beginTransaction();
  266. $result = parent::edit($data);
  267. $success = isset($result['success'])? $result['success'] : '';
  268. if($success != true){
  269. DB::rollBack();
  270. RedisService::clear($cacheKey);
  271. return message('审核失败',false);
  272. }
  273. // 消息通知
  274. $orderNo = isset($info['order_no'])? $info['order_no'] : '';
  275. if($data['status'] == 2){
  276. // 打款
  277. $payOrderId = '';
  278. $payType = isset($info['pay_type'])? $info['pay_type'] : 0;
  279. $account = isset($info['account']) && $info['account']? json_decode($info['account'], true) : [];
  280. $openid = isset($account['openid'])? $account['openid'] : '';
  281. $realname = isset($account['realname'])? $account['realname'] : '';
  282. $account = isset($account['account'])? $account['account'] : '';
  283. if($paStatus == 20 && in_array($payType,[10,20])){
  284. if($payType == 20 && empty($account)){
  285. DB::rollBack();
  286. RedisService::clear($cacheKey);
  287. return message('该用户未设置支付宝收款账号,打款失败',false);
  288. }
  289. else if($payType == 10 && empty($openid)){
  290. DB::rollBack();
  291. RedisService::clear($cacheKey);
  292. return message('该用户未授权绑定微信,打款失败',false);
  293. }
  294. $order = [
  295. 'order_no'=> $orderNo,
  296. 'pay_money'=> $data['actual_money'],
  297. 'real_name'=> $realname,
  298. 'account'=> $payType == 10? $openid : $account,
  299. 'body'=> '余额提现',
  300. ];
  301. $scene = $info['user_type']==1? 'withdraw' : 'driverWithdraw';
  302. if(!$payResult = PaymentService::make()->transfer($order,$scene, $payType)){
  303. DB::rollBack();
  304. RedisService::clear($cacheKey);
  305. return message(PaymentService::make()->getError(),false);
  306. }
  307. $orderId = isset($payResult['order_id'])? $payResult['order_id'] : '';
  308. if($orderId){
  309. $this->model->where(['id'=> $id])->update(['transaction_id'=> $orderId,'update_time'=> time()]);
  310. }
  311. }
  312. // 退钱给用户
  313. if($info['user_type'] == 1){
  314. $userInfo = isset($info['member'])?$info['member']:[];
  315. $balance = isset($userInfo['balance'])?$userInfo['balance']: 0;
  316. $updateData = [
  317. 'withdraw_total'=> DB::raw("withdraw_total + {$info['money']}"),
  318. 'update_time'=> time(),
  319. ];
  320. if(!MemberModel::where(['id'=> $info['user_id'],'mark'=>1],)->update($updateData)){
  321. DB::rollBack();
  322. RedisService::clear($cacheKey);
  323. return message('提现审核处理失败',false);
  324. }
  325. // 明细
  326. $log = [
  327. 'user_id' => $info['user_id'],
  328. 'source_id' => 0,
  329. 'source_order_no' => isset($info['order_no'])? $info['order_no'] :'',
  330. 'type' => 8, // 提现退还
  331. 'coin_type' => 4,
  332. 'user_type'=> 1,
  333. 'money' => -$info['money'],
  334. 'balance' => $balance,
  335. 'create_time' => time(),
  336. 'update_time' => time(),
  337. 'remark' => '提现成功',
  338. 'status' => 1,
  339. 'mark' => 1,
  340. ];
  341. }else if($info['user_type'] == 2){
  342. $userInfo = isset($info['driver'])?$info['driver']:[];
  343. $balance = isset($userInfo['balance'])?$userInfo['balance']: 0;
  344. $updateData = [
  345. 'withdraw_total'=> DB::raw("withdraw_total + {$info['money']}"),
  346. 'update_time'=> time(),
  347. ];
  348. if(!DriverModel::where(['id'=> $info['user_id'],'mark'=>1],)->update($updateData)){
  349. DB::rollBack();
  350. RedisService::clear($cacheKey);
  351. return message('提现审核处理失败',false);
  352. }
  353. // 明细
  354. $log = [
  355. 'user_id' => $info['user_id'],
  356. 'source_id' => 0,
  357. 'source_order_no' => isset($info['order_no'])? $info['order_no'] :'',
  358. 'type' => 8, // 提现退还
  359. 'coin_type' => 4,
  360. 'user_type'=> 2,
  361. 'money' => -$info['money'],
  362. 'balance' => $balance,
  363. 'create_time' => time(),
  364. 'update_time' => time(),
  365. 'remark' => '提现成功',
  366. 'status' => 1,
  367. 'mark' => 1,
  368. ];
  369. }else{
  370. DB::rollBack();
  371. RedisService::clear($cacheKey);
  372. return message('类型错误',false);
  373. }
  374. if ($log && !AccountLogModel::insertGetId($log)) {
  375. DB::rollBack();
  376. RedisService::clear($cacheKey);
  377. return message('提现审核账户处理失败',false);
  378. }
  379. $params = [
  380. 'title' => "余额提现审核成功通知",
  381. 'description' => "您的余额提现订单【{$orderNo}】已审核通过,请及时查看订单进度",
  382. 'type' => 3, // 1-公告通知,2-订单通知,3-交易通知,4-其他
  383. 'content' => json_encode([
  384. 'order_no' => ['name' => '订单号', 'text' => $orderNo],
  385. 'catch_time' => ['name' => '审核时间', 'text' => date('Y-m-d H:i:s')],
  386. 'money' => ['name' => '提现金额', 'text' => $info['money']],
  387. 'actual_money' => ['name' => '到账金额', 'text' => $data['actual_money']],
  388. 'remark' => ['name' => '审核备注', 'text' => $data['audit_remark']],
  389. 'status' => ['name' => '状态', 'text' => '审核通过'],
  390. ], 256),
  391. 'bind_id' => $id,
  392. ];
  393. // 推送消息给用户处理
  394. MessageService::make()->pushMessage($info['user_id'], $params, $info['user_type']);
  395. }
  396. // 审核失败
  397. else if ($data['status'] == 3){
  398. // 退钱给用户
  399. $balance = 0;
  400. if($info['user_type'] == 1){
  401. $userInfo = isset($info['member'])?$info['member']:[];
  402. $balance = isset($userInfo['balance'])?$userInfo['balance']: 0;
  403. $updateData = [
  404. 'balance'=> DB::raw("balance + {$info['money']}"),
  405. 'update_time'=> time(),
  406. ];
  407. if(!MemberModel::where(['id'=> $info['user_id'],'mark'=>1],)->update($updateData)){
  408. DB::rollBack();
  409. RedisService::clear($cacheKey);
  410. return message('提现审核处理失败',false);
  411. }
  412. }else if($info['user_type'] == 2){
  413. $userInfo = isset($info['driver'])?$info['driver']:[];
  414. $balance = isset($userInfo['balance'])?$userInfo['balance']: 0;
  415. $updateData = [
  416. 'balance'=> DB::raw("balance + {$info['money']}"),
  417. 'update_time'=> time(),
  418. ];
  419. if(!DriverModel::where(['id'=> $info['user_id'],'mark'=>1],)->update($updateData)){
  420. DB::rollBack();
  421. RedisService::clear($cacheKey);
  422. return message('提现审核处理失败',false);
  423. }
  424. }else{
  425. DB::rollBack();
  426. RedisService::clear($cacheKey);
  427. return message('类型错误',false);
  428. }
  429. // 明细
  430. $log = [
  431. 'user_id' => $info['user_id'],
  432. 'source_id' => 0,
  433. 'source_order_no' => isset($info['order_no'])? $info['order_no'] :'',
  434. 'type' => 8, // 提现退还
  435. 'coin_type' => 4,
  436. 'user_type'=> $info['user_type'],
  437. 'money' => $info['money'],
  438. 'balance' => $balance,
  439. 'create_time' => time(),
  440. 'update_time' => time(),
  441. 'remark' => '提现失败退还',
  442. 'status' => 1,
  443. 'mark' => 1,
  444. ];
  445. if (!AccountLogModel::insertGetId($log)) {
  446. DB::rollBack();
  447. RedisService::clear($cacheKey);
  448. return message('提现审核账户处理失败',false);
  449. }
  450. $params = [
  451. 'title' => "余额提现审核失败通知",
  452. 'description' => "您的余额提现订单【{$orderNo}】已审核失败,请及时查看订单进度",
  453. 'type' => 3, // 1-公告通知,2-订单通知,3-交易通知,4-其他
  454. 'content' => json_encode([
  455. 'order_no' => ['name' => '订单号', 'text' => $orderNo],
  456. 'catch_time' => ['name' => '审核时间', 'text' => date('Y-m-d H:i:s')],
  457. 'money' => ['name' => '提现金额', 'text' => $info['money']],
  458. 'actual_money' => ['name' => '退还金额', 'text' => $info['money']],
  459. 'remark' => ['name' => '审核备注', 'text' => $data['audit_remark']],
  460. 'status' => ['name' => '状态', 'text' => '审核失败'],
  461. ], 256),
  462. 'bind_id' => $id,
  463. ];
  464. // 推送消息给用户处理
  465. MessageService::make()->pushMessage($info['user_id'], $params, $info['user_type']);
  466. }
  467. // 设置日志标题
  468. ActionLogModel::setTitle("提现审核");
  469. ActionLogModel::record();
  470. DB::commit();
  471. return $result;
  472. }
  473. /**
  474. * 车型选项
  475. * @param int $num
  476. * @return array|mixed
  477. */
  478. public function getOptions($type=0, $num = 20)
  479. {
  480. $cacheKey = "caches:index:freight_package_{$type}";
  481. $datas = RedisService::get($cacheKey);
  482. if($datas){
  483. return $datas;
  484. }
  485. $where = ['status'=>1,'mark'=>1];
  486. $datas = $this->model->where($where)
  487. ->where(function($query) use($type){
  488. if($type){
  489. $query->whereIn('type',[0, $type]);
  490. }
  491. })
  492. ->select(['id','name','type','status'])
  493. ->limit($num)
  494. ->orderBy('sort','desc')
  495. ->orderBy('id','asc')
  496. ->get();
  497. $datas = $datas? $datas->toArray() : [];
  498. if($datas){
  499. RedisService::set($cacheKey, $datas, rand(5, 10));
  500. }
  501. return $datas;
  502. }
  503. }