UserController.php 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974
  1. <?php
  2. namespace App\Http\Controllers\Admin;
  3. use App\Filters\GroupSendSmsFilter;
  4. use App\Filters\RefundBalanceOrderFilter;
  5. use App\Filters\StudentFilter;
  6. use App\Filters\UserFilter;
  7. use App\Http\Requests\GroupSendSmsRequest;
  8. use App\Http\Requests\StudentRequest;
  9. use App\Http\Requests\UserRequest;
  10. use App\Http\Resources\GroupSendSmsResource;
  11. use App\Http\Resources\RefundBalanceOrderResource;
  12. use App\Http\Resources\StudentResource;
  13. use App\Http\Resources\UserResource;
  14. use App\Http\Resources\WalletResource;
  15. use App\Jobs\SendSMSJob;
  16. use App\Models\AdminMerchant;
  17. use App\Models\AdminUser;
  18. use App\Models\AdminUserArea;
  19. use App\Models\Area;
  20. use App\Models\Auth;
  21. use App\Models\Config;
  22. use App\Models\DepositOrder;
  23. use App\Models\DepositRefund;
  24. use App\Models\GroupSendSms;
  25. use App\Models\Order;
  26. use App\Models\OrderRent;
  27. use App\Models\RechargeOrder;
  28. use App\Models\RefundBalanceOrder;
  29. use App\Models\RefundLog;
  30. use App\Models\Student;
  31. use App\Models\User;
  32. use App\Models\WalletLog;
  33. use App\Utils\Admin;
  34. use App\Utils\RedisKeys;
  35. use Carbon\Carbon;
  36. use Illuminate\Database\Eloquent\Builder;
  37. use Illuminate\Http\Request;
  38. use App\Http\Controllers\Controller;
  39. use Illuminate\Support\Facades\Cache;
  40. use Illuminate\Support\Facades\DB;
  41. use Illuminate\Support\Facades\Log;
  42. /**
  43. * Class UserController
  44. * @package App\Http\Controllers\Admin
  45. */
  46. class UserController extends Controller
  47. {
  48. /**
  49. * index 用户列表
  50. *
  51. * @param UserFilter $filter
  52. * @return \Illuminate\Http\JsonResponse
  53. * @author Fx
  54. *
  55. */
  56. public function index(UserFilter $filter)
  57. {
  58. $admin_id = Admin::user()->id;
  59. $users = User::query()
  60. ->filter($filter)
  61. ->where(AdminMerchant::getMerchantWhere())
  62. ->where('is_register', User::REGISTER_OK)
  63. ->orderByDesc('id');
  64. if (!Admin::isAdministrator() && !Admin::isNormalAdministrator()) {
  65. $area_ids = AdminUser::getAreaIdsByAdminId($admin_id);
  66. if (count($area_ids) !== 0) {
  67. $users = $users->where(function ($q) use ($area_ids) {
  68. $q->whereIn('register_area_id', $area_ids)->orWhere('register_area_id', 0);
  69. });
  70. } else {
  71. $area_id = AdminUserArea::query()->where('admin_id', $admin_id)->first('area_id');
  72. $area_id = $area_id->area_id ?? 0;
  73. $users = $users->where(function ($q) use ($area_id) {
  74. $q->where('register_area_id', $area_id)->orWhere('register_area_id', 0);
  75. });
  76. }
  77. }
  78. $users = $users->paginate();
  79. return $this->ok(UserResource::collection($users));
  80. }
  81. /**
  82. * update 更新用户信息
  83. *
  84. * @param UserRequest $request
  85. * @param User $user
  86. * @return \Illuminate\Http\JsonResponse
  87. * @author Fx
  88. *
  89. */
  90. public function update(UserRequest $request, User $user)
  91. {
  92. $inputs = $request->validated();
  93. $user->update($inputs);
  94. return $this->created(UserResource::make($user));
  95. }
  96. /**
  97. * userNumber总用户数 总有效用户数
  98. *
  99. * @return \Illuminate\Http\JsonResponse
  100. * @author Fx
  101. *
  102. */
  103. public function userNumber()
  104. {
  105. $admin_id = Admin::user()->id;
  106. $data['user_total'] = User::query()->where(AdminMerchant::getMerchantWhere());
  107. $data['user_true_total'] = User::query()->where('is_card_certified', User::CARD_OK)->where(AdminMerchant::getMerchantWhere());
  108. if (!Admin::isAdministrator()) {
  109. $area_ids = AdminUser::getAreaIdsByAdminId($admin_id);
  110. if (count($area_ids) !== 0) {
  111. $data['user_total'] = $data['user_total']->whereIn('register_area_id', $area_ids);
  112. $data['user_true_total'] = $data['user_true_total']->whereIn('register_area_id', $area_ids);
  113. } else {
  114. $area_id = AdminUserArea::query()->where('admin_id', $admin_id)->first('area_id');
  115. $area_id = $area_id->area_id ?? 0;
  116. $data['user_total'] = $data['user_total']->where('register_area_id', $area_id);
  117. $data['user_true_total'] = $data['user_true_total']->where('register_area_id', $area_id);
  118. }
  119. }
  120. $data['user_total'] = $data['user_total']->count('id');
  121. $data['user_true_total'] = $data['user_true_total']->count('id');
  122. return $this->ok($data);
  123. }
  124. /**
  125. * moneySum 总充值数 总余额数
  126. * @return \Illuminate\Http\JsonResponse
  127. * @author Fx
  128. *
  129. */
  130. public function moneySum()
  131. {
  132. $admin_id = Admin::user()->id;
  133. $data['recharge_total'] = User::query()->where(AdminMerchant::getMerchantWhere());
  134. $data['wallet_money_total'] = User::query()->where(AdminMerchant::getMerchantWhere());;
  135. if (!Admin::isAdministrator()) {
  136. $area_ids = AdminUser::getAreaIdsByAdminId($admin_id);
  137. if (count($area_ids) !== 0) {
  138. $data['recharge_total'] = $data['recharge_total']->whereIn('register_area_id', $area_ids);
  139. $data['wallet_money_total'] = $data['wallet_money_total']->whereIn('register_area_id', $area_ids);
  140. } else {
  141. $area_id = AdminUserArea::query()->where('admin_id', $admin_id)->first('area_id');
  142. $area_id = $area_id->area_id ?? 0;
  143. $data['recharge_total'] = $data['recharge_total']->where('register_area_id', $area_id);
  144. $data['wallet_money_total'] = $data['wallet_money_total']->where('register_area_id', $area_id);
  145. }
  146. }
  147. $data['recharge_total'] = $data['recharge_total']->sum('recharge');
  148. $data['wallet_money_total'] = $data['wallet_money_total']->sum('wallet_money');
  149. return $this->ok($data);
  150. }
  151. /**
  152. * wallet 钱包列表
  153. *
  154. * @param Request $request
  155. * @return \Illuminate\Http\JsonResponse *@author Fx
  156. *
  157. */
  158. public function wallet(Request $request)
  159. {
  160. $user_id = $request->get('user_id') ?? '';
  161. if (empty($user_id)) return $this->error('参数错误');
  162. if (AdminMerchant::isUserToMch($user_id)) return $this->error('参数错误请刷新后重试!');
  163. $wallet = WalletLog::query()
  164. ->where('user_id', $user_id)
  165. ->orderByDesc('id')
  166. ->paginate();
  167. return $this->ok(WalletResource::collection($wallet));
  168. }
  169. /**
  170. * changeStatus 改变用户status
  171. *
  172. * @param Request $request
  173. * @return \Illuminate\Http\JsonResponse *@author Fx
  174. *
  175. */
  176. public function changeStatus(Request $request)
  177. {
  178. $user_id = $request->get('user_id') ?? '';
  179. $status = $request->get('status') ?? 0;
  180. $is_card_certified = $request->get('is_card_certified') ?? 0;
  181. $is_bind_mobile = $request->get('is_bind_mobile') ?? 0;
  182. $is_match_ride_age = $request->get('is_match_ride_age') ?? 0;
  183. $truename = $request->get('truename') ?? '';
  184. $card_id = $request->get('card_id') ?? '';
  185. $mobile = $request->get('mobile') ?? '';
  186. // $reason = $request->get('reason') ?? ''; //封号原因
  187. if (empty($user_id)) return $this->error('参数错误');
  188. try {
  189. $bool = User::query()->where('id', $user_id)->update([
  190. 'truename' => $truename,
  191. 'card_id' => $card_id,
  192. 'mobile' => $mobile,
  193. 'status' => $status,
  194. 'is_bind_mobile' => $is_bind_mobile,
  195. 'is_card_certified' => $is_card_certified,
  196. 'is_match_ride_age' => $is_match_ride_age,
  197. ]);
  198. } catch (\Exception $e) {
  199. Log::info($e->getMessage());
  200. return $this->error("修改失败,请联系管理员");
  201. }
  202. if ($bool) {
  203. return $this->created();
  204. } else {
  205. return $this->error("修改失败,请联系管理员");
  206. }
  207. }
  208. /**
  209. * returnDeposit 退还押金
  210. *
  211. * @param Request $request
  212. * @return \Illuminate\Http\JsonResponse
  213. * @author Fx
  214. *
  215. */
  216. public function returnDeposit(Request $request)
  217. {
  218. $user_id = $request->get('user_id') ?? '';
  219. if (empty($user_id)) return $this->error('参数错误');
  220. $user = User::find($user_id);
  221. if (empty($user)) return $this->error('找不到该用户信息');
  222. $order = Order::query()->where('user_id', $user_id)
  223. ->whereIn('status', [Order::STATUS_RIDE_BIKE, Order::STATUS_PAUSE_BIKE, Order::STATUS_CLOSE_BIKE])
  224. ->first();
  225. if (!empty($order)) return $this->error('该用户还有未完成得订单');
  226. $orderRent = OrderRent::query()->where('user_id', $user_id)
  227. ->whereIn('status', [OrderRent::STATUS_RENT_BIKE, OrderRent::STATUS_CLOSE_RENT_BIKE])
  228. ->first();
  229. if (!empty($orderRent)) return $this->error('该用户还有未完成得日租订单');
  230. // 此验证暂时不验证 防止交两次押金无法退还
  231. // if($user->is_deposit == User::DEPOSIT_NO) return $this->error('此用户还没缴纳押金');
  232. $depositOrder = DepositOrder::where('user_id', $user_id)->where('pay_status', DepositOrder::PAY_STATUS_OK)->where('is_refund', DepositOrder::REFUND_NO)->orderBy('id', 'desc')->first();
  233. if (empty($depositOrder)) return $this->error('此用户还没缴纳押金');
  234. if (DepositRefund::where('deposit_id', $depositOrder->id)->where('pay_status', DepositRefund::PAY_STATUS_OK)->exists()) {
  235. $depositOrder->is_refund = DepositOrder::REFUND_OK;
  236. $depositOrder->save();
  237. return $this->ok('此押金已退还');
  238. }
  239. if ($refund = DepositRefund::where('deposit_id', $depositOrder->id)->where('pay_status', DepositRefund::PAY_STATUS_NO)->first()) {
  240. $url = config('systemConfig.api_url') . '/api/payments/wechat-refund-api' . '?no=' . $depositOrder->no . '&is-order-no=1';
  241. $data = [
  242. 'no' => $depositOrder->no,
  243. 'is-order-no' => 1
  244. ];
  245. $res = curl_request($url, 'get', $data);
  246. $res = json_decode($res, true);
  247. if ($res['status']) {
  248. return $this->ok('退款已成功');
  249. }
  250. //需要重新发起退款
  251. if ($res['code'] === 'REFUNDNOTEXIST') {
  252. $payment = app('wechat.payment'); // 微信支付
  253. $result = $payment->refund->byOutTradeNumber($depositOrder->no, $refund->no, wechat_fee($depositOrder->pay_money), wechat_fee($refund->pay_money), [
  254. // 可在此处传入其他参数,详细参数见微信支付文档
  255. 'refund_desc' => '退押金',
  256. 'notify_url' => config('wechat.payment.refund_deposit_notify_url')
  257. ]);
  258. if ($result['return_code'] === 'SUCCESS') {
  259. DB::commit();
  260. return $this->ok('退还发起成功,请耐心等待');
  261. } else {
  262. Log::error(php2js($result));
  263. DB::rollBack();
  264. return $this->error('退还失败,请联系管理员' . php2js($result));
  265. }
  266. }
  267. return $this->error($res['msg']);
  268. }
  269. // if ($user->deposit_type == User::DEPOSIT_CARD) return $this->error('此用户是押金卡,还没缴纳押金');
  270. try {
  271. DB::beginTransaction();
  272. // 1.添加记录
  273. $refund = DepositRefund::firstOrCreate([
  274. 'deposit_id' => $depositOrder->id,
  275. 'user_id' => $user_id,
  276. ], [
  277. 'no' => DepositRefund::makeNo(),
  278. 'money' => $depositOrder->pay_money,
  279. 'type' => DepositRefund::TYPE_USER,
  280. 'is_check_status' => DepositRefund::CHECK_STATUS_OK,
  281. 'area_id' => $depositOrder->area_id,
  282. 'pay_type' => $depositOrder->pay_type,
  283. 'pay_money' => $depositOrder->pay_money,
  284. 'pay_status' => DepositRefund::PAY_STATUS_NO
  285. ]);
  286. //2.修改用户押金
  287. $deposit_expire_time = Carbon::parse($user->deposit_expire_time);
  288. if (Carbon::now()->gte($deposit_expire_time)) {
  289. // 免押金卡已经过期
  290. User::where('id', $user_id)->update([
  291. 'deposit_money' => 0,
  292. 'is_deposit' => User::DEPOSIT_NO,
  293. 'deposit_type' => User::DEPOSIT_TYPE_NO
  294. ]);
  295. } else {
  296. // 免押金卡未过期
  297. User::where('id', $user_id)->update([
  298. 'deposit_money' => 0,
  299. 'is_deposit' => User::DEPOSIT_OK,
  300. 'deposit_type' => User::DEPOSIT_CARD
  301. ]);
  302. }
  303. // User::where('id', $user_id)->update([
  304. // 'deposit_money' => 0,
  305. // 'is_deposit' => User::DEPOSIT_NO
  306. // ]);
  307. //3.微信退款
  308. $payment = app('wechat.payment'); // 微信支付
  309. $result = $payment->refund->byOutTradeNumber($depositOrder->no, $refund->no, wechat_fee($depositOrder->pay_money), wechat_fee($refund->pay_money), [
  310. // 可在此处传入其他参数,详细参数见微信支付文档
  311. 'refund_desc' => '退押金',
  312. 'notify_url' => config('wechat.payment.refund_deposit_notify_url')
  313. ]);
  314. $refund->save();
  315. if ($result['return_code'] === 'SUCCESS') {
  316. DB::commit();
  317. return $this->ok('退还发起成功,请耐心等待');
  318. } else {
  319. Log::error(php2js($result));
  320. DB::rollBack();
  321. return $this->error('退还失败,请联系管理员' . php2js($result));
  322. }
  323. } catch (\Exception $e) {
  324. Log::error($e->getMessage());
  325. DB::rollBack();
  326. return $this->error('退还失败,请联系管理员');
  327. }
  328. }
  329. /**
  330. * 重新发起退还押金
  331. *
  332. * @param Request $request
  333. * @return \Illuminate\Http\JsonResponse
  334. * @author Fx
  335. *
  336. */
  337. public function reReturnDeposit(Request $request)
  338. {
  339. $refund_no = $request->get('refund_no') ?? '';
  340. if (empty($refund_no)) return $this->error('参数错误');
  341. $refundLog = RefundLog::query()->where('no', $refund_no)->first();
  342. if (empty($refundLog)) return $this->error('找不到退款记录');
  343. $depositOrder = DepositOrder::query()->find($refundLog->deposit_id);
  344. if (empty($depositOrder)) return $this->error('找不到押金卡记录');
  345. $payment = app('wechat.payment'); // 微信支付
  346. $result = $payment->refund->byOutTradeNumber($depositOrder->no, $refundLog->no, wechat_fee($depositOrder->pay_money), wechat_fee($refundLog->pay_money), [
  347. // 可在此处传入其他参数,详细参数见微信支付文档
  348. 'refund_desc' => '退押金',
  349. 'notify_url' => config('wechat.payment.refund_deposit_notify_url')
  350. ]);
  351. if ($result['return_code'] === 'SUCCESS') {
  352. return $this->ok('退还发起成功,请耐心等待');
  353. } else {
  354. Log::error(php2js($result));
  355. return $this->error('退还失败,请联系管理员' . php2js($result));
  356. }
  357. }
  358. /**
  359. * groupSendSms 群发短信表单
  360. *
  361. * @param GroupSendSmsRequest $groupSendSmsRequest
  362. * @return \Illuminate\Http\JsonResponse
  363. * @author Fx
  364. *
  365. */
  366. public function groupSendSms(GroupSendSmsRequest $groupSendSmsRequest)
  367. {
  368. $template_id = $groupSendSmsRequest->get('template_id');
  369. $area_id = $groupSendSmsRequest->get('area_id');
  370. $is_deposit = $groupSendSmsRequest->get('is_deposit');
  371. $params = $groupSendSmsRequest->get('domains');
  372. $is_card_certified = $groupSendSmsRequest->get('is_card_certified');
  373. $ids = $groupSendSmsRequest->get('ids');
  374. $is_search = $groupSendSmsRequest->get('is_search');
  375. $users = User::query()
  376. ->where('is_deposit', $is_deposit)
  377. ->where('register_area_id', $area_id)
  378. ->where('is_card_certified', $is_card_certified)
  379. ->where('is_bind_mobile', User::BIND_MOBILE_OK);
  380. // 判断是否使用高级勾选
  381. if ($is_search == '1') {
  382. if (count($ids) == 0) {
  383. return $this->error('没有勾选人员');
  384. }
  385. $users = $users->whereIn('id', $ids);
  386. }
  387. $users = $users->get();
  388. // Log::info($params);
  389. try {
  390. foreach ($users as $v) {
  391. $data = [];
  392. foreach ($params as $k => $param) {
  393. switch ($param['value']) {
  394. case 'now':
  395. $value = Carbon::now()->format('Y-m-d H:i:s');
  396. break;
  397. case 'truename':
  398. $value = $v->truename;
  399. break;
  400. default:
  401. $value = $param['value'];
  402. }
  403. $data[$k] = $value;
  404. }
  405. SendSMSJob::dispatch($v->mobile, $template_id, $data);
  406. }
  407. GroupSendSms::create([
  408. 'area_id' => $area_id,
  409. 'template_id' => $template_id,
  410. 'is_deposit' => $is_deposit,
  411. 'is_card_certified' => $is_card_certified,
  412. 'is_search' => $is_search,
  413. 'ids' => empty($ids) ? "" : json_encode($ids),
  414. 'params' => empty($params) ? "" : json_encode($params),
  415. ]);
  416. return $this->ok('操作成功');
  417. } catch (\Exception $e) {
  418. Log::error($e->getMessage());
  419. return $this->error('出现错误,请联系管理员');
  420. }
  421. }
  422. /**
  423. * groupSendSmsList 群发短信列表
  424. *
  425. * @param GroupSendSmsFilter $filter
  426. * @return \Illuminate\Http\JsonResponse
  427. * @author Fx
  428. *
  429. */
  430. public function groupSendSmsList(GroupSendSmsFilter $filter)
  431. {
  432. $list = GroupSendSms::query()
  433. ->filter($filter)
  434. ->orderByDesc('id')
  435. ->where(AdminMerchant::getMerchantWhere())
  436. ->paginate();
  437. return $this->ok(GroupSendSmsResource::collection($list));
  438. }
  439. /**
  440. * groupSmsTemplate 短信模板
  441. *
  442. * @return \Illuminate\Http\JsonResponse
  443. * @author Fx
  444. *
  445. */
  446. public function groupSmsTemplate()
  447. {
  448. $smsConfigSlug = config('systemConfig.sort.sms_template.slug');
  449. $template = Config::query()->whereHas('category', function ($q) use ($smsConfigSlug) {
  450. $q->where('slug', $smsConfigSlug);
  451. })->get()->toArray();
  452. return $this->ok($template);
  453. }
  454. /**
  455. * getUserByMobile 根据手机获得用户
  456. *
  457. * @param Request $request
  458. * @return \Illuminate\Http\JsonResponse
  459. * @author Fx
  460. *
  461. */
  462. public function getUserByMobile(Request $request)
  463. {
  464. $mobile = $request->get('mobile') ?? '';
  465. if (empty($mobile)) return $this->error('参数错误');
  466. $user = User::where('mobile', $mobile)->first();
  467. if (empty($user)) return $this->error('找不到该用户');
  468. return $this->ok($user->toArray());
  469. }
  470. /**
  471. * rechargeBalance 充值余额
  472. *
  473. * @param Request $request
  474. * @return \Illuminate\Http\JsonResponse
  475. * @author Fx
  476. *
  477. */
  478. public function rechargeBalance(Request $request)
  479. {
  480. $mobile = $request->get('mobile') ?? '';
  481. $money = $request->get('money') ?? '';
  482. $remark = $request->get('remark') ?? '';
  483. if (empty($mobile) || empty($money) || empty($remark)) return $this->error('参数错误');
  484. if ($money == 0) return $this->error('金额不能为0');
  485. $users = User::query()
  486. ->where('mobile', $mobile)
  487. ->first();
  488. if (empty($users)) return $this->error('找不到该用户,请检查手机号是否正确');
  489. try {
  490. DB::beginTransaction();
  491. // 1.生成充值订单
  492. $data = [
  493. 'area_id' => $users->register_area_id,
  494. 'recharge_money' => $money,
  495. 'preferential_money' => 0.00,
  496. 'total_money' => 0.00,
  497. 'pay_money' => 0.00,
  498. 'pay_time' => Carbon::now(),
  499. 'user_id' => $users->id,
  500. 'no' => RechargeOrder::makeNo(),
  501. 'pay_status' => RechargeOrder::PAY_STATUS_OK,
  502. 'pay_type' => RechargeOrder::PAY_TYPE_SYSTERM,
  503. 'recharge_config' => '',
  504. 'is_admin' => Admin::user()->id,
  505. 'remark' => $remark,
  506. ];
  507. $order = RechargeOrder::create($data);
  508. // 2.钱包记录
  509. WalletLog::log(WalletLog::OPERATE_TYPE_ADD, $order->recharge_money, $users->id, WalletLog::TYPE_ADD_ADMIN_TO_WALLET, $order->area_id, $order->id, RechargeOrder::class);
  510. // 3.增加用户余额 (上边已做)
  511. DB::commit();
  512. return $this->ok('充值成功');
  513. } catch (\Exception $exception) {
  514. DB::rollBack();
  515. Log::error($exception->getMessage());
  516. return $this->error($exception->getMessage());
  517. }
  518. }
  519. /**
  520. * refundBalance 退还余额(附带查询)
  521. *
  522. * @param Request $request
  523. * @return \Illuminate\Http\JsonResponse
  524. * @author Fx
  525. *
  526. */
  527. public function refundBalance(Request $request)
  528. {
  529. $id = $request->get('id') ?? '';
  530. $type = $request->get('type') ?? '';
  531. if (empty($id) || empty($type)) return $this->error('参数错误');
  532. $user = User::find($id);
  533. if (empty($user)) return $this->error('找不到该用户');
  534. $refundBalanceOrder = RefundBalanceOrder::query()->where('user_id', $id)->orderByDesc('id')->first();
  535. // 用户现有余额
  536. $balance_now = $user->wallet_money;
  537. // 实际充值支付金额
  538. $total_pay_recharge = RechargeOrder::query()
  539. ->where('user_id', $id)
  540. ->where('pay_status', RechargeOrder::PAY_STATUS_OK);
  541. if (empty($refundBalanceOrder)) {
  542. $total_pay_recharge = $total_pay_recharge->sum('pay_money');
  543. } else {
  544. $total_pay_recharge = $total_pay_recharge
  545. ->where('created_at', '>', Carbon::parse($refundBalanceOrder->created_at)->format('Y-m-d H:i:s'))
  546. ->sum('pay_money');
  547. }
  548. //
  549. $rechargeOrders = RechargeOrder::query()
  550. ->where('user_id', $id)
  551. ->where('pay_status', RechargeOrder::PAY_STATUS_OK);
  552. if (empty($refundBalanceOrder)) {
  553. $rechargeOrders = $rechargeOrders->get();
  554. } else {
  555. $rechargeOrders = $rechargeOrders
  556. ->where('created_at', '>', Carbon::parse($refundBalanceOrder->created_at)->format('Y-m-d H:i:s'))
  557. ->get();
  558. }
  559. // 充值订单总充值金额
  560. $total_recharge = 0;
  561. if (!empty($rechargeOrders)) {
  562. foreach ($rechargeOrders as $v) {
  563. if (empty($v->recharge_config)) {
  564. $total_recharge = bcadd($v->recharge_money, $total_recharge, 2);
  565. } else {
  566. // Log::info($v->recharge_config);
  567. $rechargeConfig = json_decode($v->recharge_config, true);
  568. if (empty($rechargeConfig)) {
  569. $total_recharge = bcadd($v->recharge_money, $total_recharge, 2);
  570. } else {
  571. $total_recharge = bcadd(bcadd($rechargeConfig['recharge_money'], $rechargeConfig['give_money'], 2), $total_recharge, 2);
  572. }
  573. }
  574. }
  575. }
  576. // 已消费
  577. // $consumed = bcsub($total_recharge, $balance_now, 2) < 0 ? 0 : bcsub($total_recharge, $balance_now, 2);
  578. $consumed = WalletLog::query()->whereIn('type', [WalletLog::TYPE_SUB_WALLET_BIKE_ORDER, WalletLog::TYPE_ADMIN_SUB_BIKE_ORDER, WalletLog::TYPE_SUB_WALLET_RENT_ORDER])->where('user_id', $user->id);
  579. if (!empty($refundBalanceOrder)) {
  580. $consumed = $consumed
  581. ->where('created_at', '>', Carbon::parse($refundBalanceOrder->created_at)->format('Y-m-d H:i:s'));
  582. }
  583. $consumed = $consumed->sum('money');
  584. $consumed = -$consumed;
  585. $consumed = $consumed < 0 ? 0 : $consumed;
  586. // 订单返还得钱可退
  587. $order_refund_money = WalletLog::query()->where('type', WalletLog::TYPE_ADMIN_ADD_TO_WALLET)->where('user_id', $user->id);
  588. if (!empty($refundBalanceOrder)) {
  589. $order_refund_money = $order_refund_money->where('created_at', '>', Carbon::parse($refundBalanceOrder->created_at)->format('Y-m-d H:i:s'));
  590. }
  591. $order_refund_money = $order_refund_money->sum('money');
  592. // Log::info($order_refund_money);
  593. // 可退还
  594. $money = bcadd(bcsub($total_pay_recharge, $consumed, 2), $order_refund_money, 2);
  595. $money = $user->wallet_money < $money ? $user->wallet_money : $money;
  596. // 如果退款 必须从余额减去得钱 实际从余额扣除得
  597. $subBalance = bcadd($total_recharge, $order_refund_money, 2);
  598. $userBalance = $user->wallet_money < $subBalance ? $user->wallet_money : $subBalance;
  599. switch ($type) {
  600. case 'query_refund':
  601. return $this->ok([
  602. 'balance_now' => $balance_now,
  603. 'total_pay_recharge' => $total_pay_recharge,
  604. 'total_recharge' => $total_recharge,
  605. 'order_refund_money' => $order_refund_money,
  606. 'consumed' => $consumed,
  607. 'money' => $money < 0 ? 0 : $money,
  608. 'subBalance' => $userBalance
  609. ]);
  610. break;
  611. case 'refund_balance':
  612. if (Cache::has(sprintf(RedisKeys::REFUND_BALANCE, $user->id))) {
  613. return $this->error('此操作5分钟仅可操作一次');
  614. } else {
  615. Cache::add(sprintf(RedisKeys::REFUND_BALANCE, $user->id), 1, Carbon::now()->addMinutes(5));
  616. }
  617. if ($money <= 0) return $this->error('不可退款');
  618. // 新增订单
  619. $order = RefundBalanceOrder::create(
  620. [
  621. 'no' => RefundBalanceOrder::makeNo(),
  622. 'user_id' => $user->id,
  623. 'area_id' => $user->register_area_id,
  624. 'admin_id' => Admin::user()->id,
  625. 'balance_now' => $balance_now,
  626. 'total_pay_recharge' => $total_pay_recharge,
  627. 'total_recharge' => $total_recharge,
  628. 'consumed' => $consumed,
  629. 'sub_balance' => $userBalance,
  630. 'refund_money' => $money < 0 ? 0 : $money,
  631. 'pay_money' => $money < 0 ? 0 : $money,
  632. ]
  633. );
  634. $payment = app('wechat.payment'); // 微信支付
  635. $res = $payment->transfer->toBalance([
  636. 'partner_trade_no' => $order->no, // 商户订单号,需保持唯一性(只能是字母或者数字,不能包含有符号)
  637. 'openid' => $user->auth->credential,
  638. 'check_name' => 'FORCE_CHECK', // NO_CHECK:不校验真实姓名, FORCE_CHECK:强校验真实姓名
  639. 're_user_name' => $user->truename, // 如果 check_name 设置为FORCE_CHECK,则必填用户真实姓名
  640. 'amount' => wechat_fee($order->pay_money), // 企业付款金额,单位为分
  641. 'desc' => '余额退款', // 企业付款操作说明信息。必填
  642. ]);
  643. // 更新钱包记录
  644. WalletLog::log(WalletLog::OPERATE_TYPE_SUB, $userBalance, $user->id, WalletLog::TYPE_SUB_WALLET, $order->area_id, $order->id, RefundBalanceOrder::class);
  645. if ($res['return_code'] === 'SUCCESS') {
  646. if ($res['result_code'] === 'SUCCESS') {
  647. // 更新订单
  648. $order->pay_time = Carbon::now();
  649. $order->pay_status = RefundBalanceOrder::PAY_STATUS_OK;
  650. $order->save();
  651. return $this->ok('操作成功');
  652. } else {
  653. $order->err_code = $res['err_code'];
  654. $order->save();
  655. Log::error($res);
  656. return $this->error('退款失败,错误码为' . $res['err_code'] . ';具体原因请联系管理员查看');
  657. }
  658. } else {
  659. $order->err_code = $res['err_code'];
  660. $order->save();
  661. Log::error($res);
  662. return $this->error('退款失败,错误码为' . $res['err_code'] . ';具体原因请联系管理员查看');
  663. }
  664. break;
  665. default:
  666. return $this->error('类型参数错误');
  667. }
  668. }
  669. /**
  670. * refundBalanceOrderList 退余额订单
  671. *
  672. * @param RefundBalanceOrderFilter $filter
  673. * @return \Illuminate\Http\JsonResponse
  674. * @author Fx
  675. *
  676. */
  677. public function refundBalanceOrderList(RefundBalanceOrderFilter $filter)
  678. {
  679. $list = RefundBalanceOrder::filter($filter)->where(AdminMerchant::getMerchantWhere())->orderByDesc('id');
  680. $area_ids = AdminUser::getAreaIdsByAdminId(Admin::user()->id);
  681. $list = $list->whereIn('area_id', $area_ids)->paginate();
  682. return $this->ok(RefundBalanceOrderResource::collection($list));
  683. }
  684. /**
  685. * refundBalanceAgain 重试退余额订单
  686. *
  687. * @param Request $request
  688. * @return \Illuminate\Http\JsonResponse
  689. * @author Fx
  690. *
  691. */
  692. public function refundBalanceAgain(Request $request)
  693. {
  694. $no = $request->get('no') ?? '';
  695. if (empty($no)) return $this->error('参数错误');
  696. $order = RefundBalanceOrder::query()->where('no', $no)->first();
  697. if (empty($order)) return $this->error('参数错误,找不到该订单');
  698. $user = User::find($order->user_id);
  699. if (Cache::has(sprintf(RedisKeys::REFUND_BALANCE_AGAIN, $user->id))) {
  700. return $this->error('此操作1分钟仅可操作一次');
  701. } else {
  702. Cache::add(sprintf(RedisKeys::REFUND_BALANCE_AGAIN, $user->id), 1, Carbon::now()->addMinutes(1));
  703. }
  704. $payment = app('wechat.payment'); // 微信支付
  705. $res = $payment->transfer->toBalance([
  706. 'partner_trade_no' => $order->no, // 商户订单号,需保持唯一性(只能是字母或者数字,不能包含有符号)
  707. 'openid' => $user->auth->credential,
  708. 'check_name' => 'FORCE_CHECK', // NO_CHECK:不校验真实姓名, FORCE_CHECK:强校验真实姓名
  709. 're_user_name' => $user->truename, // 如果 check_name 设置为FORCE_CHECK,则必填用户真实姓名
  710. 'amount' => wechat_fee($order->pay_money), // 企业付款金额,单位为分
  711. 'desc' => '余额退款', // 企业付款操作说明信息。必填
  712. ]);
  713. if ($res['return_code'] === 'SUCCESS') {
  714. if ($res['result_code'] === 'SUCCESS') {
  715. // 更新订单
  716. $order->pay_time = Carbon::now();
  717. $order->pay_status = RefundBalanceOrder::PAY_STATUS_OK;
  718. $order->save();
  719. // 更新用户余额
  720. // $userBalance = $user->wallet_money < $subBalance ? $user->wallet_money : $subBalance ;
  721. // 更新钱包记录
  722. WalletLog::log(WalletLog::OPERATE_TYPE_SUB, $order->sub_balance, $user->id, WalletLog::TYPE_SUB_WALLET, $order->area_id, $order->id, RefundBalanceOrder::class);
  723. return $this->ok('操作成功');
  724. } else {
  725. $order->err_code = $res['err_code'];
  726. $order->save();
  727. Log::error($res);
  728. return $this->error('退款失败,错误码为' . $res['err_code'] . ';具体原因请联系管理员查看');
  729. }
  730. } else {
  731. $order->err_code = $res['err_code'];
  732. $order->save();
  733. Log::error($res);
  734. return $this->error('退款失败,错误码为' . $res['err_code'] . ';具体原因请联系管理员查看');
  735. }
  736. }
  737. /**
  738. * queryRefundBalance 查询退余额是否成功
  739. *
  740. * @param Request $request
  741. * @return \Illuminate\Http\JsonResponse
  742. * @author Fx
  743. *
  744. */
  745. public function queryRefundBalance(Request $request)
  746. {
  747. $no = $request->get('no') ?? '';
  748. if (empty($no)) return $this->error('参数错误');
  749. $order = RefundBalanceOrder::query()->where('no', $no)->first();
  750. if (empty($order)) return $this->error('找不到订单');
  751. $payment = app('wechat.payment'); // 微信支付
  752. $res = $payment->transfer->queryBalanceOrder($no);
  753. if ($res['return_code'] === 'SUCCESS') {
  754. if ($res['result_code'] === 'SUCCESS') {
  755. if ($res['status'] === 'SUCCESS') {
  756. // 更新订单
  757. if ($order->pay_status == RefundBalanceOrder::PAY_STATUS_NO) {
  758. $order->pay_time = Carbon::now();
  759. $order->pay_status = RefundBalanceOrder::PAY_STATUS_OK;
  760. $order->save();
  761. }
  762. $comments = WalletLog::query()->where('log_type', RefundBalanceOrder::class)->where('log_id', $order->id)->first();
  763. if (empty($comments)) {
  764. // 更新钱包记录
  765. WalletLog::log(WalletLog::OPERATE_TYPE_SUB, $order->sub_balance, $order->user_id, WalletLog::TYPE_SUB_WALLET, $order->area_id, $order->id, RefundBalanceOrder::class);
  766. }
  767. return $this->ok('已成功退款');
  768. } elseif ($res['status'] === 'FAILED') {
  769. Log::error($res);
  770. return $this->error('转账失败,具体原因请联系管理员');
  771. } elseif ($res['status'] === 'PROCESSING') {
  772. Log::info($res);
  773. return $this->ok('转账处理中,请耐心等待');
  774. }
  775. } else {
  776. Log::error($res);
  777. return $this->error('查询失败,具体原因请联系管理员');
  778. }
  779. } else {
  780. return $this->error('请求失败');
  781. }
  782. }
  783. /**
  784. * 认证列表
  785. * Author: Mead
  786. */
  787. public function students(StudentFilter $filter)
  788. {
  789. $admin_id = Admin::user()->id;
  790. $students = Student::query()
  791. ->filter($filter)
  792. ->with(['user', 'resource'])
  793. ->orderByDesc('id');
  794. $students = $students->paginate();
  795. return $this->ok(StudentResource::collection($students));
  796. }
  797. /**
  798. * 待处理认证信息
  799. * @return mixed
  800. * Author: Mead
  801. */
  802. public function studentsNumber()
  803. {
  804. return Student::where('auth_status', Student::AUTH_STATUS_WAIT)->count();
  805. }
  806. /**
  807. * 调整成功
  808. * @param StudentRequest $request
  809. * @return \Illuminate\Http\JsonResponse
  810. * Author: Mead
  811. */
  812. public function updateStudents(StudentRequest $request)
  813. {
  814. $data = $request->only(['id', 'auth_status', 'auth_date', 'error_msg']);
  815. $data['admin_id'] = Admin::user()->id;
  816. if (Student::where('id', $data['id'])->where('auth_status', Student::AUTH_STATUS_OK)->where('auth_date', '>', date("Y-m"))->exists()) {
  817. return $this->error('已经认证');
  818. }
  819. $student = Student::where('id', $data['id'])->orderByDesc('id')->first();
  820. if ($data['auth_status'] === Student::AUTH_STATUS_OK) {
  821. //认证成功处理
  822. $user = User::where('id', $student->user_id)->first();
  823. if ((int)$user->deposit_type === User::DEPOSIT_CARD) {
  824. $deposit_expire_time = Carbon::parse($user->deposit_expire_time);
  825. if (Carbon::parse($data['auth_date'])->gt($deposit_expire_time)) {
  826. //判断第一个日期是否比第二个日期大
  827. $user->deposit_expire_time = Carbon::parse($data['auth_date']);
  828. }
  829. } else {
  830. $user->deposit_expire_time = Carbon::parse($data['auth_date']);
  831. }
  832. if ((int)$user->is_deposit === User::DEPOSIT_NO) {
  833. $user->deposit_type = User::DEPOSIT_CARD;
  834. $user->is_deposit = User::DEPOSIT_OK;
  835. }
  836. $user->is_student = User::IS_STUDENT_OK;
  837. $user->save();
  838. }
  839. Student::where('id', $student->id)->update($data);
  840. return $this->ok();
  841. }
  842. }