UserController.php 43 KB

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