WithdrawDepositService.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. <?php
  2. namespace services\member;
  3. use Yii;
  4. use yii\base\InvalidConfigException;
  5. use yii\db\ActiveRecord;
  6. use yii\web\NotFoundHttpException;
  7. use yii\web\UnprocessableEntityHttpException;
  8. use common\components\Service;
  9. use common\enums\StatusEnum;
  10. use common\enums\TransferTypeEnum;
  11. use common\enums\WithdrawTransferStatusEnum;
  12. use common\helpers\ArrayHelper;
  13. use common\models\member\WithdrawDeposit;
  14. use EasyWeChat\Kernel\Exceptions\InvalidArgumentException;
  15. use EasyWeChat\Kernel\Exceptions\RuntimeException;
  16. use EasyWeChat\Kernel\Support\Collection;
  17. use GuzzleHttp\Exception\GuzzleException;
  18. use Omnipay\Common\Exception\InvalidRequestException;
  19. use Psr\Http\Message\ResponseInterface;
  20. /**
  21. * Class WithdrawDepositService
  22. * @package services\member
  23. */
  24. class WithdrawDepositService extends Service
  25. {
  26. /**
  27. * 转账
  28. *
  29. * @param WithdrawDeposit $model
  30. */
  31. public function transfer(WithdrawDeposit $model)
  32. {
  33. $model->transfer_name = TransferTypeEnum::getValue($model->transfer_type);
  34. $model->transfer_time = time();
  35. switch ($model->transfer_type) {
  36. // 微信转账到微信零钱
  37. case TransferTypeEnum::WECHAT_BALANCE :
  38. return $this->wechatToBalance($model);
  39. break;
  40. // 微信转账到银行卡
  41. case TransferTypeEnum::WECHAT_BANK_CARD :
  42. return $this->wechatToBankCard($model);
  43. break;
  44. // 支付宝转账到支付宝账号
  45. case TransferTypeEnum::ALI_BALANCE :
  46. return $this->alipayToAccount($model);
  47. break;
  48. }
  49. }
  50. /**
  51. * 提现到零钱
  52. *
  53. * @param WithdrawDeposit $model
  54. * @throws UnprocessableEntityHttpException
  55. * @throws InvalidArgumentException
  56. * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
  57. * @throws GuzzleException
  58. */
  59. public function wechatToBalance(WithdrawDeposit $model)
  60. {
  61. $params = [
  62. 'out_batch_no' => $model->batch_no, // 商户系统内部的商家批次单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一
  63. 'batch_name' => '批量转账 - ' . $model->realname, // 转账标题
  64. 'batch_remark' => '批量转账 - ' . $model->realname, // 转账备注
  65. 'total_amount' => $model->cash * 100, // 转账总金额
  66. 'total_num' => 1, // 转账总金额
  67. 'transfer_detail_list' => [
  68. [
  69. 'out_detail_no' => $model->withdraw_no, // 商户订单号
  70. 'transfer_amount' => $model->cash * 100, // 企业付款金额,单位为分
  71. 'transfer_remark' => !empty($model->memo) ? $model->memo : '无', // 企业付款操作说明信息。必填
  72. 'openid' => $model->account_number,
  73. 'user_name' => $model->realname, // 明细转账金额 >= 2,000,收款用户姓名必填
  74. ],
  75. ],
  76. ];
  77. $result = Yii::$app->pay->wechat->transfer($params);
  78. $model->transfer_no = $result['payment_no'];
  79. $model->transfer_account_no = $result['mch_id'];
  80. $model->save();
  81. return $result;
  82. }
  83. /**
  84. * 小程序提现
  85. *
  86. * @param WithdrawDeposit $model
  87. * @return array|Collection|object|ResponseInterface|string
  88. * @throws UnprocessableEntityHttpException
  89. * @throws InvalidArgumentException
  90. * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
  91. * @throws GuzzleException
  92. */
  93. public function wechatMiniProgramToBalance(WithdrawDeposit $model)
  94. {
  95. // 设置appid
  96. Yii::$app->params['wechatPaymentConfig'] = ArrayHelper::merge(Yii::$app->params['wechatPaymentConfig'], [
  97. 'app_id' => Yii::$app->services->config->backendConfig('wechat_mini_app_id'),
  98. ]);
  99. return $this->wechatToBalance($model);
  100. }
  101. /**
  102. * 提现到银行卡
  103. *
  104. * @param WithdrawDeposit $model
  105. * @throws UnprocessableEntityHttpException
  106. * @throws InvalidArgumentException
  107. * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
  108. * @throws RuntimeException
  109. * @throws GuzzleException
  110. */
  111. public function wechatToBankCard(WithdrawDeposit $model)
  112. {
  113. $bankNumber = Yii::$app->services->bankNumber->findByBankName($model->bank_name);
  114. if (!$bankNumber) {
  115. throw new UnprocessableEntityHttpException('该银行暂时不支持提现');
  116. }
  117. $result = Yii::$app->wechat->payment->transfer->toBankCard([
  118. 'partner_trade_no' => $model->withdraw_no,
  119. 'enc_bank_no' => $model->account_number, // 银行卡号
  120. 'enc_true_name' => $model->realname, // 银行卡对应的用户真实姓名
  121. 'bank_code' => $bankNumber->bank_number, // 银行编号
  122. 'amount' => $model->cash * 100, // 企业付款金额,单位为分
  123. 'desc' => $model->memo, // 企业付款操作说明信息。必填
  124. ]);
  125. if ($result['return_code'] != 'SUCCESS' || $result['result_code'] != 'SUCCESS') {
  126. throw new UnprocessableEntityHttpException($result['err_code_des']);
  127. }
  128. // 记录日志
  129. $model->transfer_no = $result['payment_no'];
  130. $model->transfer_account_no = $result['mch_id'];
  131. $model->save();
  132. return $result;
  133. }
  134. /**
  135. * 支付宝单次转账
  136. *
  137. * @param WithdrawDeposit $model
  138. * @return mixed
  139. * @throws InvalidRequestException
  140. * @throws InvalidConfigException
  141. */
  142. public function alipayToAccount(WithdrawDeposit $model)
  143. {
  144. $result = Yii::$app->pay->alipay->transfer([
  145. 'out_biz_no' => $model->withdraw_no,
  146. 'trans_amount' => $model->cash,
  147. 'payee_info' => [
  148. 'identity' => $model->account_number, // 提现账号
  149. 'name' => $model->realname, // 提现金额
  150. ],
  151. 'remark' => $model->memo, // 非必填
  152. ]);
  153. if ($result['code'] != '10000') {
  154. if (isset($result['sub_msg'])) {
  155. throw new UnprocessableEntityHttpException($result['sub_msg']);
  156. }
  157. throw new UnprocessableEntityHttpException($result['msg']);
  158. }
  159. // 记录日志
  160. $model->transfer_no = $result['order_id'];
  161. $model->save();
  162. return $result;
  163. }
  164. /**
  165. * @var string[]
  166. */
  167. protected $wechatStatus = [
  168. 'SUCCESS' => '转账成功',
  169. 'FAILED' => '转账失败',
  170. 'PROCESSING' => '处理中',
  171. ];
  172. /**
  173. * @param $withdraw_no
  174. * @param bool $allReturn
  175. * @return mixed
  176. * @throws NotFoundHttpException
  177. * @throws UnprocessableEntityHttpException
  178. * @throws InvalidRequestException
  179. */
  180. public function queryByWithdrawNo($withdraw_no, $allReturn = false)
  181. {
  182. $log = $this->findByWithdrawNo($withdraw_no);
  183. if (!$log) {
  184. throw new NotFoundHttpException('找不到转账记录');
  185. }
  186. switch ($log->transfer_type) {
  187. case TransferTypeEnum::ALI_BANK_CARD :
  188. case TransferTypeEnum::ALI_BALANCE :
  189. $result = Yii::$app->pay->alipay->find([
  190. 'out_biz_no' => $withdraw_no,
  191. '_type' => 'transfer',
  192. ]);
  193. return $allReturn ? $result : $result['msg'];
  194. break;
  195. case TransferTypeEnum::WECHAT_BANK_CARD :
  196. $result = Yii::$app->wechat->payment->transfer->queryBankCardOrder($withdraw_no);
  197. if ($result['return_code'] != 'SUCCESS' || $result['result_code'] != 'SUCCESS') {
  198. throw new UnprocessableEntityHttpException($result['reason']);
  199. }
  200. return $this->wechatStatus[$result['status']];
  201. break;
  202. case TransferTypeEnum::WECHAT_BALANCE :
  203. $result = Yii::$app->wechat->payment->transfer->queryBalanceOrder($withdraw_no);
  204. if ($result['return_code'] != 'SUCCESS' || $result['result_code'] != 'SUCCESS') {
  205. throw new UnprocessableEntityHttpException($result['reason']);
  206. }
  207. return $this->wechatStatus[$result['status']];
  208. break;
  209. }
  210. throw new UnprocessableEntityHttpException('无效的记录');
  211. }
  212. /**
  213. * @return int|string
  214. */
  215. public function getWithdrawalSuccessSum($addon_name = '', $member_id = '')
  216. {
  217. return WithdrawDeposit::find()
  218. ->where(['status' => StatusEnum::ENABLED])
  219. ->andWhere(['is_addon' => !empty($addon_name) ? StatusEnum::ENABLED : StatusEnum::DISABLED])
  220. ->andWhere(['transfer_status' => WithdrawTransferStatusEnum::TRANSFER_SUCCESS])
  221. ->andFilterWhere(['addon_name' => $addon_name])
  222. ->andFilterWhere(['member_id' => $member_id])
  223. ->andFilterWhere(['merchant_id' => $this->getMerchantId()])
  224. ->sum('cash') ?? 0;
  225. }
  226. /**
  227. * @return int
  228. */
  229. public function getWithdrawalCashApplySum($addon_name = '', $member_id = '')
  230. {
  231. return WithdrawDeposit::find()
  232. ->where(['status' => StatusEnum::DISABLED])
  233. ->andWhere(['is_addon' => !empty($addon_name) ? StatusEnum::ENABLED : StatusEnum::DISABLED])
  234. ->andWhere(['transfer_status' => WithdrawTransferStatusEnum::TRANSFER_SUCCESS])
  235. ->andFilterWhere(['addon_name' => $addon_name])
  236. ->andFilterWhere(['member_id' => $member_id])
  237. ->andFilterWhere(['merchant_id' => $this->getMerchantId()])
  238. ->sum('cash') ?? 0;
  239. }
  240. /**
  241. * @param $withdraw_no
  242. * @return array|ActiveRecord|null|WithdrawDeposit
  243. */
  244. public function findByWithdrawNo($withdraw_no)
  245. {
  246. return WithdrawDeposit::find()
  247. ->where(['withdraw_no' => $withdraw_no])
  248. ->one();
  249. }
  250. /**
  251. * @return int|string
  252. */
  253. public function getApplyCount($merchant_id = '')
  254. {
  255. return WithdrawDeposit::find()
  256. ->select('id')
  257. ->where(['>=', 'status', StatusEnum::DISABLED])
  258. ->andWhere(['transfer_status' => WithdrawTransferStatusEnum::APPLY])
  259. ->andFilterWhere(['id' => $merchant_id])
  260. ->count() ?? 0;
  261. }
  262. /**
  263. * @param $id
  264. * @return array|ActiveRecord|null|WithdrawDeposit
  265. */
  266. public function findById($id)
  267. {
  268. return WithdrawDeposit::find()
  269. ->where(['id' => $id])
  270. ->one();
  271. }
  272. }
粤ICP备19079148号