V2.php 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. <?php
  2. /**
  3. * Niushop商城系统 - 团队十年电商经验汇集巨献!
  4. * =========================================================
  5. * Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
  6. * ----------------------------------------------
  7. * 官方网址: https://www.niushop.com
  8. * =========================================================
  9. */
  10. namespace addon\wechatpay\model;
  11. use app\model\BaseModel;
  12. use app\model\system\Pay as PayCommon;
  13. use app\model\upload\Upload;
  14. use EasyWeChat\Factory;
  15. /**
  16. * 微信支付v3支付
  17. * 版本 1.0.4
  18. */
  19. class V2 extends BaseModel
  20. {
  21. /**
  22. * 微信支付配置
  23. */
  24. private $config;
  25. /**
  26. * 支付实例
  27. * @var
  28. */
  29. private $app;
  30. public function __construct($config)
  31. {
  32. $this->config = $config;
  33. $this->app = Factory::payment([
  34. 'app_id' => $config['appid'], //应用id
  35. 'mch_id' => $config["mch_id"] ?? '', //商户号
  36. 'key' => $config["pay_signkey"] ?? '', // API 密钥
  37. // 如需使用敏感接口(如退款、发送红包等)需要配置 API 证书路径(登录商户平台下载 API 证书)
  38. 'cert_path' => realpath($config["apiclient_cert"]) ?? '', // apiclient_cert.pem XXX: 绝对路径!!!!
  39. 'key_path' => realpath($config["apiclient_key"]) ?? '', // apiclient_key.pem XXX: 绝对路径!!!!
  40. 'notify_url' => '',// 你也可以在下单时单独设置来想覆盖它
  41. 'response_type' => 'array',
  42. 'log' => [
  43. 'level' => 'debug',
  44. 'permission' => 0777,
  45. 'file' => 'runtime/log/wechat/easywechat.logs',
  46. ],
  47. 'sandbox' => false, // 设置为 false 或注释则关闭沙箱模式
  48. ]);
  49. }
  50. /**
  51. * 支付
  52. * @param array $param
  53. * @return array\
  54. */
  55. public function pay(array $param){
  56. $data = [
  57. 'body' => str_sub($param["pay_body"], 15),
  58. 'out_trade_no' => $param["out_trade_no"],
  59. 'total_fee' => $param["pay_money"] * 100,
  60. 'notify_url' => $param["notify_url"],
  61. 'trade_type' => $param["trade_type"] == 'APPLET' ? 'JSAPI' : $param["trade_type"]
  62. ];
  63. if ($param['trade_type'] == 'JSAPI' || $param['trade_type'] == 'APPLET') $data['openid'] = $param['openid'];
  64. $result = $this->app->order->unify($data);
  65. if ($result["return_code"] == 'FAIL') return $this->error([], $result["return_msg"]);
  66. if ($result["result_code"] == 'FAIL') return $this->error([], $result["err_code_des"]);
  67. $return = [];
  68. switch ($param["trade_type"]) {
  69. case 'JSAPI' ://微信支付 或小程序支付
  70. $return = [
  71. "type" => "jsapi",
  72. "data" => $this->app->jssdk->sdkConfig($result['prepay_id'], false)
  73. ];
  74. break;
  75. case 'APPLET' ://微信支付 或小程序支付
  76. $return = [
  77. "type" => "jsapi",
  78. "data" => $this->app->jssdk->bridgeConfig($result['prepay_id'], false)
  79. ];
  80. break;
  81. case 'NATIVE' :
  82. $upload_model = new Upload($param['site_id']);
  83. $qrcode_result = $upload_model->qrcode($result['code_url']);
  84. $return = [
  85. "type" => "qrcode",
  86. "qrcode" => $qrcode_result['data'] ?? ''
  87. ];
  88. break;
  89. case 'MWEB' ://H5支付
  90. $return = [
  91. "type" => "url",
  92. "url" => $result['mweb_url']
  93. ];
  94. break;
  95. case 'APP' :
  96. $config = $this->app->jssdk->appConfig($result['prepay_id']);
  97. $return = [
  98. "type" => "app",
  99. "data" => $config
  100. ];
  101. break;
  102. }
  103. return $this->success($return);
  104. }
  105. /**
  106. * 异步回调
  107. */
  108. public function payNotify()
  109. {
  110. $response = $this->app->handlePaidNotify(function ($message, $fail) {
  111. $pay_common = new PayCommon();
  112. if ($message['return_code'] === 'SUCCESS') {
  113. // return_code 表示通信状态,不代表支付状态
  114. if ($message['result_code'] === 'SUCCESS') {
  115. // 判断支付金额是否等于支付单据的金额
  116. $pay_info = $pay_common->getPayInfo($message['out_trade_no'])['data'];
  117. if (empty($pay_info)) return $fail('通信失败,请稍后再通知我');
  118. if ($message['total_fee'] != round($pay_info['pay_money'] * 100)) return;
  119. // 用户是否支付成功
  120. $pay_common->onlinePay($message['out_trade_no'], "wechatpay", $message["transaction_id"], "wechatpay");
  121. }
  122. } else {
  123. return $fail('通信失败,请稍后再通知我');
  124. }
  125. return true;
  126. });
  127. $response->send();
  128. return $response;
  129. }
  130. /**
  131. * 关闭支付单据
  132. * @param array $param
  133. * @return array
  134. * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
  135. * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
  136. * @throws \GuzzleHttp\Exception\GuzzleException */
  137. public function payClose(array $param)
  138. {
  139. $result = $this->app->order->close($param["out_trade_no"]);
  140. if ($result["return_code"] == 'FAIL') {
  141. return $this->error([], $result["return_msg"]);
  142. }
  143. if ($result["result_code"] == 'FAIL') {
  144. if ($result['err_code'] == 'ORDERPAID') return $this->error(['is_paid' => 1, 'pay_type' => 'wechatpay'], $result['err_code_des']);
  145. return $this->error([], $result['err_code_des']);
  146. }
  147. return $this->success();
  148. }
  149. /**
  150. * 申请退款
  151. * @param array $param
  152. */
  153. public function refund(array $param)
  154. {
  155. $pay_info = $param["pay_info"];
  156. $refund_no = $param["refund_no"];
  157. $total_fee = round($pay_info["pay_money"] * 100);
  158. $refund_fee = round($param["refund_fee"] * 100);
  159. $result = $this->app->refund->byOutTradeNumber($pay_info["out_trade_no"], $refund_no, $total_fee, $refund_fee, []);
  160. //调用失败
  161. if ($result["return_code"] == 'FAIL') return $this->error([], $result["return_msg"]);
  162. if ($result["result_code"] == 'FAIL') return $this->error([], $result["err_code_des"]);
  163. return $this->success();
  164. }
  165. /**
  166. * 转账
  167. * @param array $param
  168. * @return array\
  169. */
  170. public function transfer(array $param)
  171. {
  172. $data = [
  173. 'partner_trade_no' => $param['out_trade_no'], // 商户订单号,需保持唯一性(只能是字母或者数字,不能包含有符号)
  174. 'openid' => $param['account_number'],
  175. 'check_name' => 'FORCE_CHECK', // NO_CHECK:不校验真实姓名, FORCE_CHECK:强校验真实姓名
  176. 're_user_name' => $param['real_name'], // 如果 check_name 设置为FORCE_CHECK,则必填用户真实姓名
  177. 'amount' => $param['amount'] * 100, // 转账金额
  178. 'desc' => $param['desc']
  179. ];
  180. $res = $this->app->transfer->toBalance($data);
  181. if ($res['return_code'] == 'SUCCESS') {
  182. if ($res['result_code'] == 'SUCCESS') {
  183. return $this->success([
  184. 'out_trade_no' => $res['partner_trade_no'], // 商户交易号
  185. 'payment_no' => $res['payment_no'], // 微信付款单号
  186. 'payment_time' => $res['payment_time'] // 付款成功时间
  187. ]);
  188. } else {
  189. return $this->error([], $res['err_code_des']);
  190. }
  191. } else {
  192. return $this->error([], $res['return_msg']);
  193. }
  194. }
  195. /**
  196. * 付款码支付
  197. * @param array $param
  198. * @return array\
  199. */
  200. public function micropay(array $param){
  201. $data = [
  202. 'body' => str_sub($param["pay_body"], 15),
  203. 'out_trade_no' => $param["out_trade_no"],
  204. 'total_fee' => $param["pay_money"] * 100,
  205. 'auth_code' => $param["auth_code"]
  206. ];
  207. $result = $this->app->base->pay($data);
  208. if ($result[ 'return_code' ] == 'FAIL') {
  209. return $this->error([], $result[ 'return_msg' ]);
  210. }
  211. if ($result[ 'result_code' ] == 'FAIL') {
  212. return $this->error([], $result[ 'err_code_des' ]);
  213. }
  214. return $this->success($result);
  215. }
  216. }