Alipay.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. <?php
  2. namespace core\pay;
  3. use app\dict\pay\OnlinePayDict;
  4. use app\dict\pay\RefundDict;
  5. use app\dict\pay\TransferDict;
  6. use core\exception\PayException;
  7. use Psr\Http\Message\ResponseInterface;
  8. use Throwable;
  9. use Yansongda\Pay\Pay;
  10. use Yansongda\Supports\Collection;
  11. /**
  12. * 文件管理驱动类
  13. * Class FileDriver
  14. * @package core\file
  15. */
  16. class Alipay extends BasePay
  17. {
  18. /**
  19. * @param array $config
  20. * @return void
  21. */
  22. protected function initialize(array $config = [])
  23. {
  24. parent::initialize($config);
  25. $config['app_public_cert_path'] = url_to_path($config['app_public_cert_path'] ?? '');
  26. $config['alipay_public_cert_path'] = url_to_path($config['alipay_public_cert_path'] ?? '');
  27. $config['alipay_root_cert_path'] = url_to_path($config['alipay_root_cert_path'] ?? '');
  28. $config['mode'] = Pay::MODE_NORMAL;
  29. $this->config = $this->payConfig($config, 'alipay');
  30. Pay::config($this->config);
  31. }
  32. public function mp(array $params)
  33. {
  34. }
  35. /**
  36. * 网页支付
  37. * @param array $params
  38. * @return array
  39. */
  40. public function web(array $params)
  41. {
  42. return $this->returnFormat(Pay::alipay()->web([
  43. 'out_trade_no' => $params['out_trade_no'],
  44. 'total_amount' => $params['money'],
  45. 'subject' => $params['body'],
  46. '_method' => 'get',
  47. ]));
  48. }
  49. /**
  50. * 手机网页支付
  51. * @param array $params
  52. * @return array
  53. */
  54. public function wap(array $params)
  55. {
  56. $response = Pay::alipay()->h5([
  57. 'out_trade_no' => $params['out_trade_no'],
  58. 'total_amount' => $params['money'],
  59. 'subject' => $params['body'],
  60. 'quit_url' => $params['quit_url'] ?? '',//用户付款中途退出返回商户网站的地址, 一般是商品详情页或购物车页
  61. '_method' => 'get',
  62. ]);
  63. $redirects = $response->getHeader('Location');
  64. $effective_url = end($redirects);
  65. return ['url' => $effective_url];
  66. }
  67. /**
  68. * app支付
  69. * @param array $params
  70. * @return array
  71. */
  72. public function app(array $params)
  73. {
  74. return $this->returnFormat(Pay::alipay()->app([
  75. 'out_trade_no' => $params['out_trade_no'],
  76. 'total_amount' => $params['money'],
  77. 'subject' => $params['body'],//用户付款中途退出返回商户网站的地址, 一般是商品详情页或购物车页
  78. ]));
  79. }
  80. /**
  81. * 小程序支付
  82. * @param array $params
  83. * @return Collection
  84. */
  85. public function mini(array $params)
  86. {
  87. return Pay::alipay()->mini([
  88. 'out_trade_no' => $params['out_trade_no'],
  89. 'total_amount' => $params['money'],
  90. 'subject' => $params['body'],
  91. 'buyer_id' => $params['buyer_id'],//买家支付宝用户ID 注:交易的买家与卖家不能相同。
  92. ]);
  93. }
  94. /**
  95. * 付款码支付
  96. * @param array $params
  97. * @return Collection
  98. */
  99. public function pos(array $params)
  100. {
  101. return Pay::alipay()->pos([
  102. 'out_trade_no' => $params['out_trade_no'],
  103. 'auth_code' => $params['auth_code'],//付授权码。 当面付场景传买家的付款码(25~30开头的长度为16~24位的数字,实际字符串长度以开发者获取的付款码长度为准)或者刷脸标识串(fp开头的35位字符串)。
  104. 'total_amount' => $params['money'],
  105. 'subject' => $params['body'],
  106. ]);
  107. }
  108. /**
  109. * 扫码支付
  110. * @param array $params
  111. * @return Collection
  112. */
  113. public function scan(array $params)
  114. {
  115. return Pay::alipay()->scan([
  116. 'out_trade_no' => $params['out_trade_no'],
  117. 'total_amount' => $params['money'],
  118. 'subject' => $params['body'],
  119. ]);
  120. }
  121. /**
  122. * 转账
  123. * @param array $params
  124. * @return array
  125. */
  126. public function transfer(array $params)
  127. {
  128. $result = $this->returnFormat(Pay::alipay()->transfer([
  129. 'out_biz_no' => $params['transfer_no'],
  130. 'trans_amount' => $params['money'],
  131. 'product_code' => $params['product_code'] ?: 'TRANS_ACCOUNT_NO_PWD',//业务产品码,单笔无密转账到支付宝账户固定为 : TRANS_ACCOUNT_NO_PWD; 收发现金红包固定为 : STD_RED_PACKET;
  132. 'biz_scene' => $params['scene'] ?: 'DIRECT_TRANSFER',//描述特定的业务场景,可传的参数如下:DIRECT_TRANSFER:单笔无密转账到支付宝,B2C现金红包;PERSONAL_COLLECTION:C2C现金红包-领红包
  133. 'payee_info' => [//收款方信息
  134. 'identity' => $params['to_no'],//参与方的唯一标识
  135. 'identity_type' => $params['to_type'] ?: 'ALIPAY_LOGON_ID',//参与方的标识类型,目前支持如下类型:1、ALIPAY_USER_ID 支付宝的会员ID2、ALIPAY_LOGON_ID:支付宝登录号,支持邮箱和手机号格式3、ALIPAY_OPEN_ID:支付宝openid
  136. 'name' => $params['to_name'],//参与方真实姓名,如果非空,将校验收款支付宝账号姓名一致性。当identity_type=ALIPAY_LOGON_ID时,本字段必填。
  137. ],
  138. ]));
  139. if (!empty($result['msg']) && $result['msg'] != 'Success') {
  140. throw new PayException($result['sub_msg']);
  141. } else {
  142. $status = $result['status'];
  143. $status_array = array(
  144. 'SUCCESS' => TransferDict::SUCCESS,
  145. 'WAIT_PAY' => TransferDict::WAIT,
  146. 'CLOSED' => TransferDict::FAIL,
  147. 'FAIL' => TransferDict::FAIL
  148. );
  149. $res = array(
  150. 'status' => $status_array[$status],
  151. );
  152. if ($status == 'FAIL') {
  153. $res['fail_reason'] = $result['fail_reason'];
  154. }
  155. }
  156. return $res;
  157. }
  158. /**
  159. * 支付关闭
  160. * @param string $out_trade_no
  161. * @return bool
  162. */
  163. public function close(string $out_trade_no)
  164. {
  165. $result = $this->returnFormat(Pay::alipay()->close([
  166. 'out_trade_no' => $out_trade_no,
  167. ]));
  168. //todo 支付宝关闭异步回调
  169. if (isset($result['sub_code']) && in_array($result['sub_code'], ['ACQ.REASON_ILLEGAL_STATUS', 'ACQ.REASON_TRADE_STATUS_INVALID', 'ACQ.TRADE_NOT_EXIST', 'ACQ.TRADE_STATUS_ERROR'])) {
  170. return true;
  171. }
  172. if (!empty($result['msg']) && $result['msg'] == 'Success') {
  173. return true;
  174. } else {
  175. return false;
  176. }
  177. }
  178. /**
  179. * 退款
  180. * @param array $params
  181. * @return array|false
  182. */
  183. public function refund(array $params)
  184. {
  185. $out_trade_no = $params['out_trade_no'];
  186. $money = $params['money'];
  187. // $total = $params['total'];
  188. $refund_no = $params['refund_no'];
  189. $result = $this->returnFormat(Pay::alipay()->refund([
  190. 'out_trade_no' => $out_trade_no,
  191. 'refund_amount' => $money,
  192. 'out_request_no' => $refund_no
  193. ]));
  194. if (!empty($result['msg']) && $result['msg'] == 'Success') {
  195. $fund_change = $result['fund_change'];//退款是否成功可以根据同步响应的 fund_change 参数来判断,fund_change 表示本次退款是否发生了资金变化,返回 Y 表示退款成功,返回 N 则表示本次退款未发生资金变动 。
  196. if ($fund_change == 'Y') {
  197. $status = RefundDict::SUCCESS;
  198. } else {
  199. $status = RefundDict::DEALING;
  200. }
  201. return [
  202. 'status' => $status,
  203. 'refund_no' => $refund_no,
  204. 'out_trade_no' => $out_trade_no
  205. ];
  206. } else {
  207. //todo 这儿可以抛出错误
  208. return false;
  209. }
  210. }
  211. /**
  212. * 支部异步回调
  213. * @param string $action
  214. * @param callable $callback
  215. * @return ResponseInterface|string
  216. */
  217. public function notify(string $action, callable $callback)
  218. {
  219. try {
  220. $result = Pay::alipay()->callback();
  221. //通过返回的值
  222. if (!empty($result)) {//成功
  223. if ($action == 'pay') {
  224. //todo 这儿需要具体设计
  225. $temp_data = array(
  226. 'mchid' => $result['seller_id'],
  227. 'trade_no' => $result['trade_no'],
  228. 'result' => $result,
  229. 'status' => OnlinePayDict::getAliPayStatus($result['trade_status'])
  230. );
  231. $callback_result = $callback($result['out_trade_no'], $temp_data);
  232. if (is_bool($callback_result) && $callback_result) {
  233. return Pay::alipay()->success();
  234. }
  235. }
  236. }
  237. return $this->fail();
  238. } catch ( Throwable $e ) {
  239. return $this->fail();
  240. }
  241. }
  242. /**
  243. * 查询普通支付订单
  244. * @param array $params
  245. * @return array
  246. */
  247. public function getOrder(array $params = [])
  248. {
  249. $out_trade_no = $params['out_trade_no'];
  250. $order = [
  251. 'out_trade_no' => $out_trade_no,
  252. ];
  253. $result = $this->returnFormat(Pay::alipay()->query($order));
  254. if (!empty($result['msg']) && $result['msg'] == 'Success') {
  255. return [
  256. 'status' => OnlinePayDict::getAliPayStatus($result['trade_status'])
  257. ];
  258. } else {
  259. if (!empty($result['sub_code']) && $result['sub_code'] == 'ACQ.ACQ.SYSTEM_ERROR') {
  260. throw new PayException($result['msg']);
  261. } else {
  262. return [];
  263. }
  264. }
  265. }
  266. /**
  267. * 查询退款单据
  268. * @param string $out_trade_no
  269. * @param string|null $refund_no
  270. * @return array
  271. */
  272. public function getRefund(string $out_trade_no, ?string $refund_no)
  273. {
  274. $order = [
  275. 'out_trade_no' => $out_trade_no,
  276. 'out_request_no' => $refund_no,
  277. '_action' => 'refund', // 默认值,查询退款网页订单
  278. ];
  279. $result = $this->returnFormat(Pay::alipay()->query($order));
  280. if (!empty($result['msg']) && $result['msg'] == 'Success') {
  281. $refund_status = $result['refund_status'] ?? '';
  282. if ($refund_status == 'REFUND_SUCCESS') {
  283. $status = RefundDict::SUCCESS;
  284. } else {
  285. $status = RefundDict::DEALING;
  286. }
  287. return [
  288. 'status' => $status,
  289. 'refund_no' => $refund_no,
  290. 'out_trade_no' => $out_trade_no
  291. ];
  292. } else {
  293. if (!empty($result['sub_code']) && $result['sub_code'] == 'ACQ.ACQ.SYSTEM_ERROR') {
  294. throw new PayException($result['msg']);
  295. } else {
  296. return [];
  297. }
  298. }
  299. }
  300. /**
  301. * 获取转账订单
  302. * @param string $transfer_no
  303. * @return array
  304. */
  305. public function getTransfer(string $transfer_no, $out_transfer_no = '')
  306. {
  307. $order = [
  308. 'out_biz_no' => $transfer_no,
  309. '_action' => 'transfer'
  310. ];
  311. $result = $this->returnFormat(Pay::alipay()->query($order));
  312. if (!empty($result['msg']) && $result['msg'] == 'Success') {
  313. $status = $result['SUCCESS'] ?? '';
  314. $status_array = array(
  315. 'SUCCESS' => TransferDict::SUCCESS,
  316. 'WAIT_PAY' => TransferDict::WAIT,
  317. 'CLOSED' => TransferDict::FAIL,
  318. 'FAIL' => TransferDict::FAIL
  319. );
  320. return [
  321. 'status' => $status_array[$status],
  322. 'transfer_no' => $transfer_no
  323. ];
  324. } else {
  325. if (!empty($result['sub_code']) && $result['sub_code'] == 'ACQ.ACQ.SYSTEM_ERROR') {
  326. throw new PayException($result['msg']);
  327. } else {
  328. return [];
  329. }
  330. }
  331. }
  332. /**
  333. * 转账取消
  334. * @param array $params
  335. * @return array
  336. */
  337. public function transferCancel(array $params)
  338. {
  339. }
  340. public function fail()
  341. {
  342. return 'fail';
  343. }
  344. public function returnUrl($params)
  345. {
  346. return ['url' => $params->getHeader('Location')[0] ?? ''];
  347. }
  348. }