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.

216 lines
7.7 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
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. $msg = ['user_id' => $userId, 'storeId' => $storeId];
  63. throw new ErrorCodeException(ErrorCode::STORE_NOT_AVAILABLE,'',$msg);
  64. }
  65. $data['balance'] = UserBalance::query()
  66. ->where(['source_id' => $store->user_id, 'user_type' => UserType::STORE])
  67. ->value('balance');
  68. $data['award'] = $this->financialService->sumAmount(
  69. $store->user_id,
  70. UserType::STORE,
  71. [FinancialRecord::MONEY_TYPE_STORE_PLAT_NEW_USER, FinancialRecord::MONEY_TYPE_STORE_FIRST_ORDER]
  72. );
  73. $data['notice'] = [
  74. // [
  75. // 'title' => '用户须知',
  76. // 'content' => '<p>请仔细填写相关信息,如果由于您填写的信息有误导致资金流失,平台概不负责。</p><p>注意:因微信限制当前用户账户余额满<span style="color:red;">1</span>元后才可提现</p>'
  77. // ],
  78. [
  79. 'title' => '提现须知',
  80. 'content' => '<p>1、提金额最低为<span style="color:red;">1</span>元,最高为<span style="color:red;">5000</span>元,一天最多可提现<span style="color:red;">10</span>次。</p>'
  81. .'<p>2、提现到账时间为一个工作日内。</p>'
  82. .'<p>3、提现成功后,提现款会自动转入您当前登录的微信账号</p>'
  83. .'<p>4、如果您在提现方面遇到问题,请致电联系我们的服务站。</p>'
  84. ],
  85. ];
  86. return $this->success($data);
  87. }
  88. /**
  89. * 商户提现申请
  90. * 1、商户提现参数校验
  91. * 2、商户提现是否超过可提现金额
  92. * 3、提现是否秒到账,秒到账则打款并且做流水,否则就打到后台审核
  93. */
  94. public function applyByStore()
  95. {
  96. $isDirect = config('wechat.withdrawal.is_direct');
  97. $min = config('wechat.withdrawal.min_amount');
  98. $max = config('wechat.withdrawal.max_amount');
  99. $validator = $this->validationFactory->make(
  100. $this->request->all(),
  101. [
  102. 'user_id' => 'required|nonempty|integer',
  103. 'store_id' => 'required|nonempty|integer',
  104. 'money' => "required|nonempty|numeric|between:{$min}, {$max}",
  105. ]
  106. );
  107. if ($validator->fails()) {
  108. throw new ValidationException($validator);
  109. }
  110. $money = $this->request->input('money');
  111. $userId = $this->request->input('user_id');
  112. $storeId = $this->request->input('store_id');
  113. if ($money > 1000) {
  114. $this->log->event(LogLabel::STORE_WITHDRAW_FAIL_LOG, [
  115. 'msg' => '提现失败[1000]',
  116. 'params' => json_encode(['money' => $money, 'user_id' => $userId, 'store_id' => $storeId]),
  117. ]);
  118. throw new ErrorCodeException(ErrorCode::WITHDRAW_PAYMENT_FAIL);
  119. }
  120. $store = Store::query()->where(['user_id' => $userId, 'id' => $storeId])->first();
  121. if (empty($store)) {
  122. $msg = ['user_id' => $userId, 'storeId' => $storeId];
  123. throw new ErrorCodeException(ErrorCode::STORE_NOT_AVAILABLE, '' , $msg);
  124. }
  125. // 校验余额
  126. $balance = UserBalance::query()
  127. ->where(['source_id' => $store->user_id, 'user_type' => UserType::STORE])
  128. ->first();
  129. if ($money > $balance->balance) {
  130. throw new ErrorCodeException(
  131. ErrorCode::STORE_WITHDRAW_INSUFFICIENT_BALANCE,
  132. '',
  133. ['message' => 'store withdraw balance not enough','data' => ['user_id' => $userId, 'store_id' => $storeId, 'money' => $money, 'balance' => $balance->balance]]
  134. );
  135. }
  136. Db::beginTransaction();
  137. try {
  138. $storeUser = User::query()->find($store->user_id);
  139. $currentTime = time();
  140. // 获取分布式全局ID
  141. $generator = ApplicationContext::getContainer()->get(IdGeneratorInterface::class);
  142. $globalOrderId = $generator->generate();
  143. // 记录提现申请记录
  144. $withdraw = new StoreWithdrawal();
  145. $withdraw->trade_no = $globalOrderId;
  146. $withdraw->store_id = $store->id;
  147. $withdraw->name = $storeUser->nick_name ?: '';
  148. $withdraw->tel = $storeUser->tel;
  149. $withdraw->apply_cash = $money;
  150. $withdraw->save();
  151. // 先扣除余额
  152. $balance->balance = bcsub($balance->balance, $money, 2);
  153. $balance->save();
  154. // 如果秒到账无需审核的话
  155. if ($isDirect) {
  156. // 打款
  157. $res = $this->paymentService->payToWx(
  158. bcmul($withdraw->apply_cash, 100 , 0),
  159. $withdraw->trade_no,
  160. $storeUser->openid,
  161. $withdraw->name,
  162. '商户 ['.$store->name.'] 提现打款'
  163. );
  164. // 更新打款金额,审核时间等
  165. $withdraw->check_time = time();
  166. $withdraw->real_cash = $money;
  167. $withdraw->state = 2;
  168. $withdraw->save();
  169. // 打款成功,写流水
  170. if ($res === true) {
  171. $this->financialService->storeWithdrawByWx($store->user_id, $withdraw->id, $withdraw->real_cash);
  172. }
  173. }
  174. Db::commit();
  175. return $this->success([]);
  176. } catch (\Exception $e) {
  177. Db::rollBack();
  178. $this->log->event(LogLabel::STORE_WITHDRAW_FAIL_LOG, [
  179. 'msg' => $e->getMessage(),
  180. 'withdraw' => json_encode($withdraw),
  181. 'params' => json_encode(['balance' => $balance->balance, 'user_id' => $userId, 'store_id' => $storeId]),
  182. ]);
  183. throw new ErrorCodeException(ErrorCode::WITHDRAW_PAYMENT_FAIL);
  184. }
  185. }
  186. }