Order.php 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | WeChatDeveloper
  4. // +----------------------------------------------------------------------
  5. // | 版权所有 2014~2023 ThinkAdmin [ thinkadmin.top ]
  6. // +----------------------------------------------------------------------
  7. // | 官方网站: https://thinkadmin.top
  8. // +----------------------------------------------------------------------
  9. // | 开源协议 ( https://mit-license.org )
  10. // | 免责声明 ( https://thinkadmin.top/disclaimer )
  11. // +----------------------------------------------------------------------
  12. // | gitee 代码仓库:https://gitee.com/zoujingli/WeChatDeveloper
  13. // | github 代码仓库:https://github.com/zoujingli/WeChatDeveloper
  14. // +----------------------------------------------------------------------
  15. namespace WePayV3;
  16. use WeChat\Contracts\Tools;
  17. use WeChat\Exceptions\InvalidArgumentException;
  18. use WeChat\Exceptions\InvalidDecryptException;
  19. use WeChat\Exceptions\InvalidResponseException;
  20. use WePayV3\Contracts\BasicWePay;
  21. use WePayV3\Contracts\DecryptAes;
  22. /**
  23. * 直连商户 | 订单支付接口
  24. * Class Order
  25. * @package WePayV3
  26. */
  27. class Order extends BasicWePay
  28. {
  29. const WXPAY_H5 = 'h5';
  30. const WXPAY_APP = 'app';
  31. const WXPAY_JSAPI = 'jsapi';
  32. const WXPAY_NATIVE = 'native';
  33. /**
  34. * 创建支付订单
  35. * @param string $type 支付类型
  36. * @param array $data 支付参数
  37. * @return array
  38. * @throws \WeChat\Exceptions\InvalidResponseException
  39. * @document https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_1.shtml
  40. */
  41. public function create($type, $data)
  42. {
  43. $types = [
  44. 'h5' => '/v3/pay/transactions/h5',
  45. 'app' => '/v3/pay/transactions/app',
  46. 'jsapi' => '/v3/pay/transactions/jsapi',
  47. 'native' => '/v3/pay/transactions/native',
  48. ];
  49. if (empty($types[$type])) {
  50. throw new InvalidArgumentException("Payment {$type} not defined.");
  51. } else {
  52. // 创建预支付码
  53. $result = $this->doRequest('POST', $types[$type], json_encode($data, JSON_UNESCAPED_UNICODE), true);
  54. if (empty($result['h5_url']) && empty($result['code_url']) && empty($result['prepay_id'])) {
  55. $message = isset($result['code']) ? "[ {$result['code']} ] " : '';
  56. $message .= isset($result['message']) ? $result['message'] : json_encode($result, JSON_UNESCAPED_UNICODE);
  57. throw new InvalidResponseException($message);
  58. }
  59. // 支付参数签名
  60. $time = strval(time());
  61. $appid = $this->config['appid'];
  62. $nonceStr = Tools::createNoncestr();
  63. if ($type === 'app') {
  64. $sign = $this->signBuild(join("\n", [$appid, $time, $nonceStr, $result['prepay_id'], '']));
  65. return ['partnerId' => $this->config['mch_id'], 'prepayId' => $result['prepay_id'], 'package' => 'Sign=WXPay', 'nonceStr' => $nonceStr, 'timeStamp' => $time, 'sign' => $sign];
  66. } elseif ($type === 'jsapi') {
  67. $sign = $this->signBuild(join("\n", [$appid, $time, $nonceStr, "prepay_id={$result['prepay_id']}", '']));
  68. return ['appId' => $appid, 'timestamp' => $time, 'timeStamp' => $time, 'nonceStr' => $nonceStr, 'package' => "prepay_id={$result['prepay_id']}", 'signType' => 'RSA', 'paySign' => $sign];
  69. } else {
  70. return $result;
  71. }
  72. }
  73. }
  74. /**
  75. * 支付订单查询
  76. * @param string $tradeNo 订单单号
  77. * @return array
  78. * @throws \WeChat\Exceptions\InvalidResponseException
  79. * @document https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_2.shtml
  80. */
  81. public function query($tradeNo)
  82. {
  83. $pathinfo = "/v3/pay/transactions/out-trade-no/{$tradeNo}";
  84. return $this->doRequest('GET', "{$pathinfo}?mchid={$this->config['mch_id']}", '', true);
  85. }
  86. /**
  87. * 关闭支付订单
  88. * @param string $tradeNo 订单单号
  89. * @return array
  90. * @throws \WeChat\Exceptions\InvalidResponseException
  91. */
  92. public function close($tradeNo)
  93. {
  94. $data = ['mchid' => $this->config['mch_id']];
  95. $path = "/v3/pay/transactions/out-trade-no/{$tradeNo}/close";
  96. return $this->doRequest('POST', $path, json_encode($data, JSON_UNESCAPED_UNICODE), true);
  97. }
  98. /**
  99. * 支付通知解析
  100. * @param array $data
  101. * @return array
  102. * @throws \WeChat\Exceptions\InvalidDecryptException
  103. */
  104. public function notify(array $data = [])
  105. {
  106. if (empty($data)) {
  107. $data = json_decode(Tools::getRawInput(), true);
  108. }
  109. if (isset($data['resource'])) {
  110. $aes = new DecryptAes($this->config['mch_v3_key']);
  111. $data['result'] = $aes->decryptToString(
  112. $data['resource']['associated_data'],
  113. $data['resource']['nonce'],
  114. $data['resource']['ciphertext']
  115. );
  116. }
  117. return $data;
  118. }
  119. /**
  120. * 创建退款订单
  121. * @param array $data 退款参数
  122. * @return array
  123. * @throws \WeChat\Exceptions\InvalidResponseException
  124. * @document https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_9.shtml
  125. */
  126. public function createRefund($data)
  127. {
  128. $path = '/v3/refund/domestic/refunds';
  129. return $this->doRequest('POST', $path, json_encode($data, JSON_UNESCAPED_UNICODE), true);
  130. }
  131. /**
  132. * 退款订单查询
  133. * @param string $refundNo 退款单号
  134. * @return array
  135. * @throws \WeChat\Exceptions\InvalidResponseException
  136. * @document https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_10.shtml
  137. */
  138. public function queryRefund($refundNo)
  139. {
  140. $path = "/v3/refund/domestic/refunds/{$refundNo}";
  141. return $this->doRequest('GET', $path, '', true);
  142. }
  143. /**
  144. * 获取退款通知
  145. * @param string $xml
  146. * @return array
  147. * @return array
  148. * @throws \WeChat\Exceptions\InvalidDecryptException
  149. * @throws \WeChat\Exceptions\InvalidResponseException
  150. */
  151. public function notifyRefund($xml = '')
  152. {
  153. $data = Tools::xml2arr(empty($xml) ? Tools::getRawInput() : $xml);
  154. if (empty($data['return_code']) || $data['return_code'] !== 'SUCCESS') {
  155. throw new InvalidResponseException('获取退款通知失败!');
  156. }
  157. try {
  158. $decrypt = base64_decode($data['req_info']);
  159. $response = openssl_decrypt($decrypt, 'aes-256-ecb', md5($this->config['mch_v3_key']), OPENSSL_RAW_DATA);
  160. $data['result'] = Tools::xml2arr($response);
  161. return $data;
  162. } catch (\Exception $exception) {
  163. throw new InvalidDecryptException($exception->getMessage(), $exception->getCode());
  164. }
  165. }
  166. /**
  167. * 申请交易账单
  168. * @param array|string $params
  169. * @return array
  170. * @throws \WeChat\Exceptions\InvalidResponseException
  171. * @document https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_3_6.shtml
  172. */
  173. public function tradeBill($params)
  174. {
  175. $path = '/v3/bill/tradebill?' . is_array($params) ? http_build_query($params) : $params;
  176. return $this->doRequest('GET', $path, '', true);
  177. }
  178. /**
  179. * 申请资金账单
  180. * @param array|string $params
  181. * @return array
  182. * @throws \WeChat\Exceptions\InvalidResponseException
  183. * @document https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_3_7.shtml
  184. */
  185. public function fundflowBill($params)
  186. {
  187. $path = '/v3/bill/fundflowbill?' . is_array($params) ? http_build_query($params) : $params;
  188. return $this->doRequest('GET', $path, '', true);
  189. }
  190. /**
  191. * 下载账单文件
  192. * @param string $fileurl
  193. * @return string 二进制 Excel 内容
  194. * @throws \WeChat\Exceptions\InvalidResponseException
  195. * @document https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_6_1.shtml
  196. */
  197. public function downloadBill($fileurl)
  198. {
  199. return $this->doRequest('GET', $fileurl, '', false, false);
  200. }
  201. }