AlipayService.php 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. <?php
  2. namespace addons\Alitopay\common\services;
  3. use addons\Alitopay\common\enums\AlitoapyEnum;
  4. use addons\Alitopay\common\jdk\alipay\AlipayConfig;
  5. use addons\Alitopay\common\jdk\alipay\AopCertClient;
  6. use addons\Alitopay\common\jdk\alipay\AopClient;
  7. use addons\Alitopay\common\jdk\alipay\request\AlipayFundTransUniTransferRequest;
  8. use common\helpers\ArrayHelper;
  9. use common\helpers\FormatHelper;
  10. use Exception;
  11. use Omnipay\Alipay\AopPageGateway;
  12. use Omnipay\Omnipay;
  13. use RuntimeException;
  14. use Yii;
  15. class AlipayService extends BaseService
  16. {
  17. const URI = '/alitopay/notify/alipay';
  18. protected $sand_box = false;
  19. /**
  20. * @var AopPageGateway|null
  21. */
  22. protected $aop = null;
  23. public function setSandBox(bool $boolean)
  24. {
  25. $this->sand_box = $boolean;
  26. }
  27. /**
  28. * 创建支付宝AOP
  29. *
  30. * @return AopPageGateway
  31. */
  32. public function createAop(array $setting = [])
  33. {
  34. if (empty($setting) && empty($this->mall_id)) throw new \Exception('未定义Mall-Id');
  35. if (empty($setting)) $setting = (new SettingService($this->mall_id))->getSetting();
  36. /**
  37. * @var \Omnipay\Alipay\AopPageGateway
  38. */
  39. $this->aop = Omnipay::create('Alipay_AopWap');
  40. $this->aop->setSignType('RSA2'); // RSA/RSA2/MD5. Use certificate mode must set RSA2
  41. $this->aop->setAppId($setting['app_id']);
  42. $this->aop->setPrivateKey(trim($setting['private_key']));
  43. $this->aop->setAlipayPublicKey(trim($setting['alipay_public_key']));
  44. // 回调地址
  45. $this->aop->setNotifyUrl(
  46. $this->getNotifyUrl()
  47. );
  48. // 设置沙盒
  49. $this->sand_box && $this->aop->sandbox();
  50. return $this->aop;
  51. }
  52. /**
  53. * 单笔转账
  54. *
  55. * @param float $money
  56. * @param string $name
  57. * @param string $account
  58. * @param string $order_sn
  59. * @param string $payee_type
  60. * @param string $remark
  61. * @return array|string
  62. */
  63. public function transfer(
  64. float $money,
  65. string $name,
  66. string $account,
  67. string $order_sn,
  68. string $remark = AlitoapyEnum::DEF_REMARK,
  69. string $payee_type = 'ALIPAY_LOGON_ID'
  70. )
  71. {
  72. $data = [
  73. 'out_biz_no' => $order_sn,
  74. 'trans_amount' => $money,
  75. 'order_title' => $remark,
  76. 'remark' => $remark,
  77. 'payee_info' => [
  78. 'identity_type' => $payee_type,
  79. 'identity' => $account,
  80. 'name' => $name,
  81. ]
  82. ];
  83. try {
  84. return $this->alipayFundTransUniTransfer($data);
  85. } catch (Exception $e) {
  86. Yii::$app->custom->logs(FormatHelper::exception($e, '支付宝代付提现失败'), compact('data'));
  87. return ['code' => -1, 'sub_msg' => '系统异常', 'msg' => '系统异常'];
  88. }
  89. }
  90. private function isCreatedAop()
  91. {
  92. if ($this->aop === null) $this->createAop();
  93. }
  94. /**
  95. * 获取回调地址
  96. *
  97. * @return string
  98. */
  99. private function getNotifyUrl()
  100. {
  101. return Yii::$app->services->setting->platform->get('system.api_url') . static::URI;
  102. }
  103. public function getAopClient(){
  104. if (empty($setting) && empty($this->mall_id)) throw new \Exception('未定义Mall-Id');
  105. if (empty($setting)) $setting = (new SettingService($this->mall_id))->getSetting();
  106. $aop = new AopClient();
  107. $aop->gatewayUrl = 'https://openapi.alipay.com/gateway.do';
  108. $aop->appId = $setting['app_id'];
  109. $aop->rsaPrivateKey = trim($setting['private_key']);
  110. $aop->alipayrsaPublicKey=trim($setting['alipay_public_key']);
  111. $aop->apiVersion = '1.0';
  112. $aop->signType = 'RSA2';
  113. $aop->postCharset='UTF-8';
  114. $aop->format='json';
  115. return $aop;
  116. }
  117. /**
  118. * 获取配置
  119. *
  120. * 这个方法是复制上面的getAopClient
  121. * 因为上面的方法是有缺失的,但是不删,因为或许其他地方有用到
  122. * 所以针对“申请电子回单”的功能,用这个新方法,且这个“申请电子回单”的功能按照原来的代码,本就一直就用不了的
  123. * 此新方法与原方法的区别是:获取的配置rsaPrivateKey、alipayrsaPublicKey,是用全局的支付宝配置,并不是用“支付宝代付”的配置
  124. *
  125. * @throws \Exception 当未定义Mall-Id时抛出异常
  126. * @return AopClient 初始化的支付宝客户端对象
  127. */
  128. public function getAopClientMall()
  129. {
  130. if (empty($setting) && empty($this->mall_id)) throw new \Exception('未定义Mall-Id');
  131. if (empty($setting)) $setting = (new SettingService($this->mall_id))->getSetting();
  132. $settingMall = \Yii::$app->services->setting->mall->get($this->mall_id, 'pay');
  133. $settingMall = json_decode($settingMall['alipay'], true);
  134. $aop = new AopClient();
  135. $aop->gatewayUrl = 'https://openapi.alipay.com/gateway.do';
  136. $aop->appId = $settingMall['alipay_app_id'];
  137. $aop->rsaPrivateKey = trim($settingMall['alipay_private_key']);
  138. $aop->alipayrsaPublicKey = trim($settingMall['alipay_public_key']);
  139. $aop->apiVersion = '1.0';
  140. $aop->signType = 'RSA2';
  141. $aop->postCharset = 'UTF-8';
  142. $aop->format = 'json';
  143. return $aop;
  144. }
  145. /**
  146. * 获取 "alipay.fund.trans.uni.transfer(单笔转账接口)" 配置
  147. *
  148. * @param array $setting
  149. *
  150. * @return AlipayConfig
  151. * @throws Exception
  152. */
  153. protected function getAlipayConfig(array $setting = [])
  154. {
  155. if (empty($setting) && empty($this->mall_id)) throw new Exception('未定义Mall-Id');
  156. if (empty($setting)) $setting = (new SettingService($this->mall_id))->getSetting();
  157. $alipayConfig = new AlipayConfig();
  158. $alipayConfig->setPrivateKey($setting['private_key']);
  159. $alipayConfig->setServerUrl('https://openapi.alipay.com/gateway.do');
  160. $alipayConfig->setAppId($setting['app_id']);
  161. $alipayConfig->setCharset('UTF-8');
  162. $alipayConfig->setSignType('RSA2');
  163. $alipayConfig->setFormat('json');
  164. $alipayConfig->setAppCertContent($setting['app_cert']);
  165. $alipayConfig->setAlipayPublicCertContent($setting['alipay_public_key']);
  166. $alipayConfig->setRootCertContent($setting['root_cert']);
  167. return $alipayConfig;
  168. }
  169. /**
  170. * 调用 alipay.fund.trans.uni.transfer(单笔转账接口)
  171. *
  172. * @param array $data
  173. *
  174. * @return array
  175. * @throws Exception
  176. */
  177. protected function alipayFundTransUniTransfer(array $data = []): array
  178. {
  179. // 初始化SDK
  180. $alipayClient = new AopCertClient($this->getAlipayConfig());
  181. // 构造请求参数以调用接口
  182. $request = new AlipayFundTransUniTransferRequest();
  183. // 设置描述特定的业务场景
  184. !isset($data['biz_scene']) && $data['biz_scene'] = "DIRECT_TRANSFER";
  185. // 设置业务产品码
  186. !isset($data['product_code']) && $data['product_code'] = "TRANS_ACCOUNT_NO_PWD";
  187. $request->setBizContent(json_encode($data,JSON_UNESCAPED_UNICODE));
  188. $responseResult = $alipayClient->execute($request);
  189. $responseApiName = str_replace(".","_",$request->getApiMethodName())."_response";
  190. $response = $responseResult->$responseApiName;
  191. Yii::$app->custom->logs('支付宝代付请求', [
  192. 'res' => $response,
  193. 'data' => $data
  194. ]);
  195. if (empty($response)) {
  196. throw new RuntimeException('alipay.fund.trans.uni.transfer(单笔转账接口) 响应空');
  197. }
  198. if (is_array($response)) {
  199. return $response;
  200. }
  201. if (!is_object($response)) {
  202. throw new RuntimeException('alipay.fund.trans.uni.transfer(单笔转账接口) 响应参数类型错误');
  203. }
  204. return ArrayHelper::toArray($response);
  205. }
  206. }