Pay.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: Gold
  5. * Date: 2024/1/24
  6. * Time: 14:32
  7. */
  8. namespace app\api\controller;
  9. use app\admin\model\order\Order;
  10. use app\admin\model\order\OrderGoods;
  11. use app\admin\model\order\UserGoods;
  12. use app\common\controller\Api;
  13. use EasyWeChat\Factory;
  14. use think\Db;
  15. use Yansongda\Pay\Pay as YansongdaPay;
  16. use Yansongda\Pay\Log;
  17. class Pay extends Api
  18. {
  19. /**
  20. * 微信支付
  21. *
  22. */
  23. public function wxpay($arr = ''){
  24. $app_id = Db::name('config')->where('name','app_id')->value('value');
  25. $mch_id = Db::name('config')->where('name','mch_id')->value('value');
  26. $key = Db::name('config')->where('name','key')->value('value');
  27. $config = [
  28. // 必要配置
  29. 'app_id' => $app_id,
  30. 'mch_id' => $mch_id,
  31. 'key' => $key, // API v2 密钥 (注意: 是v2密钥 是v2密钥 是v2密钥)
  32. // 如需使用敏感接口(如退款、发送红包等)需要配置 API 证书路径(登录商户平台下载 API 证书)
  33. 'cert_path' => 'path/to/your/cert.pem', // XXX: 绝对路径!!!!
  34. 'key_path' => 'path/to/your/key', // XXX: 绝对路径!!!!
  35. 'notify_url' => '默认的订单回调地址', // 你也可以在下单时单独设置来想覆盖它
  36. ];
  37. $app = Factory::payment($config);
  38. $result = $app->order->unify([
  39. 'body' => '购买教材',
  40. 'out_trade_no' => $arr['out_trade_no'],
  41. 'total_fee' => $arr['total_fee'],
  42. 'notify_url' => 'https://'.$_SERVER['HTTP_HOST'].'/api/pay/wxnotify', // 支付结果通知网址,如果不设置则会使用配置里的默认地址
  43. 'trade_type' => 'JSAPI', // 请对应换成你的支付方式对应的值类型
  44. 'openid' => 'oUpF8uMuAJO_M2pxb1Q9zNjWeS6o',
  45. ]);
  46. //如trade_type = APP
  47. //需要进行二次签名
  48. (new \EasyWeChat\Payment\Jssdk\Client($app))->appConfig($result['prepay_id']);
  49. return $result;
  50. }
  51. /**
  52. * 微信回调
  53. *
  54. */
  55. public function wxnotify(){
  56. $app_id = Db::name('config')->where('name','app_id')->value('value');
  57. $mch_id = Db::name('config')->where('name','mch_id')->value('value');
  58. $key = Db::name('config')->where('name','key')->value('value');
  59. $config = [
  60. // 必要配置
  61. 'app_id' => $app_id,
  62. 'mch_id' => $mch_id,
  63. 'key' => $key, // API v2 密钥 (注意: 是v2密钥 是v2密钥 是v2密钥)
  64. // 如需使用敏感接口(如退款、发送红包等)需要配置 API 证书路径(登录商户平台下载 API 证书)
  65. 'cert_path' => 'path/to/your/cert.pem', // XXX: 绝对路径!!!!
  66. 'key_path' => 'path/to/your/key', // XXX: 绝对路径!!!!
  67. 'notify_url' => '默认的订单回调地址', // 你也可以在下单时单独设置来想覆盖它
  68. ];
  69. $app = Factory::payment($config);
  70. $response = $app->handlePaidNotify(function($message, $fail){
  71. // 使用通知里的 "微信支付订单号" 或者 "商户订单号" 去自己的数据库找到订单
  72. $OrderModel = new Order();
  73. $order = $OrderModel->where('order_on',$message['out_trade_no'])->find();
  74. if (!$order || $order->paid_at) { // 如果订单不存在 或者 订单已经支付过了
  75. return true; // 告诉微信,我已经处理完了,订单没找到,别再通知我了
  76. }
  77. ///////////// <- 建议在这里调用微信的【订单查询】接口查一下该笔订单的情况,确认是已经支付 /////////////
  78. if ($message['return_code'] === 'SUCCESS') { // return_code 表示通信状态,不代表支付状态
  79. // 用户是否支付成功
  80. if ($message['result_code'] === 'SUCCESS') {
  81. $OrderGoods = new OrderGoods();
  82. $UserGoods = new UserGoods();
  83. $OrderModel = new Order();
  84. $order = $OrderModel->where('order_on',$message['out_trade_no'])->find();
  85. $o_arr = [
  86. 'status' => 1,
  87. 'paytime' => date('Y-m-d H:i:s')
  88. ];
  89. $OrderModel->where('id',$order['id'])->update($o_arr);
  90. $goods = $OrderGoods->where('order_id',$order['id'])->select();
  91. foreach ($goods as $k => $v){
  92. $g_arr = [
  93. 'goods_type' => $v['goods_type'],
  94. 'goods_id' => $v['goods_id'],
  95. 'order_id' => $order['id'],
  96. 'user_id' => $order['user_id'],
  97. ];
  98. $UserGoods->save($g_arr);
  99. }
  100. // 用户支付失败
  101. } else{
  102. $order->status = 'paid_fail';
  103. }
  104. } else {
  105. return $fail('通信失败,请稍后再通知我');
  106. }
  107. $order->save(); // 保存订单
  108. return true; // 返回处理完成
  109. });
  110. $response->send();
  111. }
  112. /**
  113. * 支付宝支付
  114. *
  115. */
  116. public function alipay($arr){
  117. $app_id = Db::name('config')->where('name','ali_app_id')->value('value');
  118. $ali_public_key = Db::name('config')->where('name','ali_public_key')->value('value');
  119. $private_key = Db::name('config')->where('name','private_key')->value('value');
  120. $config = [
  121. 'app_id' => $app_id,
  122. 'notify_url' => 'https://'.$_SERVER['HTTP_HOST'].'/api/pay/wxnotify',
  123. 'return_url' => 'http://yansongda.cn/return.php',
  124. 'ali_public_key' => $ali_public_key,
  125. 'private_key' => $private_key,
  126. 'log' => [ // optional
  127. 'file' => './logs/alipay.log',
  128. 'level' => 'info', // 建议生产环境等级调整为 info,开发环境为 debug
  129. 'type' => 'single', // optional, 可选 daily.
  130. 'max_file' => 30, // optional, 当 type 为 daily 时有效,默认 30 天
  131. ],
  132. 'http' => [ // optional
  133. 'timeout' => 5.0,
  134. 'connect_timeout' => 5.0,
  135. // 更多配置项请参考 [Guzzle](https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html)
  136. ],
  137. // 'mode' => 'dev', // optional,设置此参数,将进入沙箱模式
  138. ];
  139. $order = [
  140. 'out_trade_no' => $arr['out_trade_no'],
  141. 'total_amount' => $arr['total_amount'],
  142. 'subject' => '购买教材',
  143. ];
  144. $alipay = YansongdaPay::alipay($config);
  145. if($arr['type'] == 'H5'){
  146. $result = $alipay->wap($order);
  147. }else{
  148. $result = $alipay->scan($order);
  149. }
  150. return $result;
  151. }
  152. public function alinotify()
  153. {
  154. $app_id = Db::name('config')->where('name','ali_app_id')->value('value');
  155. $ali_public_key = Db::name('config')->where('name','ali_public_key')->value('value');
  156. $private_key = Db::name('config')->where('name','private_key')->value('value');
  157. $config = [
  158. 'app_id' => $app_id,
  159. 'notify_url' => 'http://yansongda.cn/notify.php',
  160. 'return_url' => 'http://yansongda.cn/return.php',
  161. 'ali_public_key' => $ali_public_key,
  162. 'private_key' => $private_key,
  163. 'log' => [ // optional
  164. 'file' => './logs/alipay.log',
  165. 'level' => 'info', // 建议生产环境等级调整为 info,开发环境为 debug
  166. 'type' => 'single', // optional, 可选 daily.
  167. 'max_file' => 30, // optional, 当 type 为 daily 时有效,默认 30 天
  168. ],
  169. 'http' => [ // optional
  170. 'timeout' => 5.0,
  171. 'connect_timeout' => 5.0,
  172. // 更多配置项请参考 [Guzzle](https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html)
  173. ],
  174. // 'mode' => 'dev', // optional,设置此参数,将进入沙箱模式
  175. ];
  176. $alipay = Pay::alipay($config);
  177. try{
  178. $data = $alipay->verify(); // 是的,验签就这么简单!
  179. // 请自行对 trade_status 进行判断及其它逻辑进行判断,在支付宝的业务通知中,只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时,支付宝才会认定为买家付款成功。
  180. // 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号;
  181. // 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额);
  182. // 3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email);
  183. // 4、验证app_id是否为该商户本身。
  184. // 5、其它业务逻辑情况
  185. if($data->trade_status == 'TRADE_SUCCESS'){
  186. $OrderModel = new Order();
  187. $order = $OrderModel->where('order_on',$data->out_trade_no)->find();
  188. if (!$order) { // 如果订单不存在 或者 订单已经支付过了
  189. return $alipay->success()->send();
  190. }
  191. $OrderGoods = new OrderGoods();
  192. $UserGoods = new UserGoods();
  193. $OrderModel = new Order();
  194. $order = $OrderModel->where('order_on',$data->out_trade_no)->find();
  195. $o_arr = [
  196. 'status' => 1,
  197. 'paytime' => date('Y-m-d H:i:s')
  198. ];
  199. $OrderModel->where('id',$order['id'])->update($o_arr);
  200. $goods = $OrderGoods->where('order_id',$order['id'])->select();
  201. foreach ($goods as $k => $v){
  202. $g_arr = [
  203. 'goods_type' => $v['goods_type'],
  204. 'goods_id' => $v['goods_id'],
  205. 'order_id' => $order['id'],
  206. 'user_id' => $order['user_id'],
  207. ];
  208. $UserGoods->save($g_arr);
  209. }
  210. }
  211. Log::debug('Alipay notify', $data->all());
  212. } catch (\Exception $e) {
  213. // $e->getMessage();
  214. }
  215. return $alipay->success()->send();// laravel 框架中请直接 `return $alipay->success()`
  216. }
  217. }