You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

201 lines
7.0 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. <?php
  2. namespace App\Controller\v3;
  3. use App\Commons\Log;
  4. use App\Constants\v3\ErrorCode;
  5. use App\Constants\v3\LogLabel;
  6. use App\Constants\v3\UserType;
  7. use App\Controller\BaseController;
  8. use App\Exception\ErrorCodeException;
  9. use App\Model\v3\FinancialRecord;
  10. use App\Model\v3\Store;
  11. use App\Model\v3\StoreWithdrawal;
  12. use App\Model\v3\User;
  13. use App\Model\v3\UserBalance;
  14. use App\Service\v3\Interfaces\FinancialRecordServiceInterface;
  15. use App\Service\v3\Interfaces\PaymentServiceInterface;
  16. use Hyperf\DbConnection\Db;
  17. use Hyperf\Di\Annotation\Inject;
  18. use Hyperf\Snowflake\IdGeneratorInterface;
  19. use Hyperf\Utils\ApplicationContext;
  20. use Hyperf\Validation\ValidationException;
  21. class WithdrawController extends BaseController
  22. {
  23. /**
  24. * @Inject
  25. * @var Log
  26. */
  27. protected $log;
  28. /**
  29. * @Inject
  30. * @var FinancialRecordServiceInterface
  31. */
  32. protected $financialService;
  33. /**
  34. * @Inject
  35. * @var PaymentServiceInterface
  36. */
  37. protected $paymentService;
  38. /**
  39. * 商户提现页数据
  40. * 1、可提现金额
  41. * 2、获得的奖励金额(历史总奖励金额)
  42. * 3、用户须知
  43. * 4、提现须知
  44. */
  45. public function pageByStore()
  46. {
  47. $validator = $this->validationFactory->make(
  48. $this->request->all(),
  49. [
  50. 'user_id' => 'required|nonempty|integer',
  51. 'store_id' => 'required|nonempty|integer',
  52. ],
  53. ['*.*' => ':attribute 参数不正确']
  54. );
  55. if ($validator->fails()) {
  56. throw new ValidationException($validator);
  57. }
  58. $userId = $this->request->input('user_id');
  59. $storeId = $this->request->input('store_id');
  60. $store = Store::query()->where(['user_id' => $userId, 'id' => $storeId])->first();
  61. if (empty($store)) {
  62. throw new ErrorCodeException(ErrorCode::STORE_NOT_AVAILABLE);
  63. }
  64. $data['balance'] = UserBalance::query()
  65. ->where(['source_id' => $store->user_id, 'user_type' => UserType::STORE])
  66. ->value('balance');
  67. $data['award'] = $this->financialService->sumAmount(
  68. $store->user_id,
  69. UserType::STORE,
  70. [FinancialRecord::MONEY_TYPE_STORE_PLAT_NEW_USER, FinancialRecord::MONEY_TYPE_STORE_FIRST_ORDER]
  71. );
  72. $data['notice'] = [
  73. // [
  74. // 'title' => '用户须知',
  75. // 'content' => '<p>请仔细填写相关信息,如果由于您填写的信息有误导致资金流失,平台概不负责。</p><p>注意:因微信限制当前用户账户余额满<span style="color:red;">1</span>元后才可提现</p>'
  76. // ],
  77. [
  78. 'title' => '提现须知',
  79. 'content' => '<p>1、提金额最低为<span style="color:red;">1</span>元,最高为<span style="color:red;">5000</span>元,一天最多可提现<span style="color:red;">10</span>次。</p>'
  80. .'<p>2、提现到账时间为一个工作日内。</p>'
  81. .'<p>3、提现成功后,提现款会自动转入您当前登录的微信账号</p>'
  82. .'<p>4、如果您在提现方面遇到问题,请致电联系我们的服务站。</p>'
  83. ],
  84. ];
  85. return $this->success($data);
  86. }
  87. /**
  88. * 商户提现申请
  89. * 1、商户提现参数校验
  90. * 2、商户提现是否超过可提现金额
  91. * 3、提现是否秒到账,秒到账则打款并且做流水,否则就打到后台审核
  92. */
  93. public function applyByStore()
  94. {
  95. $isDirect = config('wechat.withdrawal.is_direct');
  96. $min = config('wechat.withdrawal.min_amount');
  97. $max = config('wechat.withdrawal.max_amount');
  98. $validator = $this->validationFactory->make(
  99. $this->request->all(),
  100. [
  101. 'user_id' => 'required|nonempty|integer',
  102. 'store_id' => 'required|nonempty|integer',
  103. 'money' => "required|nonempty|numeric|between:{$min}, {$max}",
  104. ]
  105. );
  106. if ($validator->fails()) {
  107. throw new ValidationException($validator);
  108. }
  109. $money = $this->request->input('money');
  110. $userId = $this->request->input('user_id');
  111. $storeId = $this->request->input('store_id');
  112. $store = Store::query()->where(['user_id' => $userId, 'id' => $storeId])->first();
  113. if (empty($store)) {
  114. throw new ErrorCodeException(ErrorCode::STORE_NOT_AVAILABLE, '[稍后重试]');
  115. }
  116. // 校验余额
  117. $balance = UserBalance::query()
  118. ->where(['source_id' => $store->user_id, 'user_type' => UserType::STORE])
  119. ->first();
  120. if ($money > $balance->balance) {
  121. throw new ErrorCodeException(ErrorCode::STORE_WITHDRAW_INSUFFICIENT_BALANCE);
  122. }
  123. Db::beginTransaction();
  124. try {
  125. $storeUser = User::query()->find($store->user_id);
  126. $currentTime = time();
  127. // 获取分布式全局ID
  128. $generator = ApplicationContext::getContainer()->get(IdGeneratorInterface::class);
  129. $globalOrderId = $generator->generate();
  130. // 记录提现申请记录
  131. $withdraw = new StoreWithdrawal();
  132. $withdraw->trade_no = $globalOrderId;
  133. $withdraw->store_id = $store->id;
  134. $withdraw->name = $storeUser->nick_name ?: '';
  135. $withdraw->tel = $storeUser->tel;
  136. $withdraw->apply_cash = $money;
  137. $withdraw->save();
  138. // 先扣除余额
  139. $balance->balance = bcsub($balance->balance, $money, 2);
  140. $balance->save();
  141. // 如果秒到账无需审核的话
  142. if ($isDirect) {
  143. // 打款
  144. $res = $this->paymentService->payToWx(
  145. bcmul($withdraw->apply_cash, 100 , 0),
  146. $withdraw->trade_no,
  147. $storeUser->openid,
  148. $withdraw->name,
  149. '商户 ['.$store->name.'] 提现打款'
  150. );
  151. // 更新打款金额,审核时间等
  152. $withdraw->check_time = time();
  153. $withdraw->real_cash = $money;
  154. $withdraw->state = 2;
  155. $withdraw->save();
  156. // 打款成功,写流水
  157. if ($res === true) {
  158. $this->financialService->storeWithdrawByWx($store->user_id, $withdraw->id, $withdraw->real_cash);
  159. }
  160. }
  161. Db::commit();
  162. return $this->success([]);
  163. } catch (\Exception $e) {
  164. Db::rollBack();
  165. $this->log->event(LogLabel::STORE_WITHDRAW_FAIL_LOG, [
  166. 'msg' => $e->getMessage(),
  167. 'withdraw' => json_encode($withdraw),
  168. 'params' => json_encode(['balance' => $balance->balance, 'user_id' => $userId, 'store_id' => $storeId]),
  169. ]);
  170. throw new ErrorCodeException(ErrorCode::WITHDRAW_PAYMENT_FAIL);
  171. }
  172. }
  173. }