You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

304 lines
12 KiB

  1. <?php
  2. namespace addons\epay\library;
  3. use addons\unishop\model\Config;
  4. use Exception;
  5. use think\Log;
  6. use think\Response;
  7. use think\Session;
  8. use Yansongda\Pay\Gateways\Alipay\Alipay;
  9. use Yansongda\Pay\Pay;
  10. /**
  11. * 订单服务类
  12. *
  13. * @package addons\epay\library
  14. */
  15. class Service
  16. {
  17. public static function submitOrder($amount, $orderid = null, $type = null, $title = null, $notifyurl = null, $returnurl = null, $method = null)
  18. {
  19. if (!is_array($amount)) {
  20. $params = [
  21. 'amount' => $amount,
  22. 'orderid' => $orderid,
  23. 'type' => $type,
  24. 'title' => $title,
  25. 'notifyurl' => $notifyurl,
  26. 'returnurl' => $returnurl,
  27. 'method' => $method,
  28. ];
  29. } else {
  30. $params = $amount;
  31. }
  32. $type = isset($params['type']) && in_array($params['type'], ['alipay', 'wechat']) ? $params['type'] : 'wechat';
  33. $method = isset($params['method']) ? $params['method'] : 'web';
  34. $orderid = isset($params['orderid']) ? $params['orderid'] : date("YmdHis") . mt_rand(100000, 999999);
  35. $amount = isset($params['amount']) ? $params['amount'] : 1;
  36. $title = isset($params['title']) ? $params['title'] : "支付";
  37. $auth_code = isset($params['auth_code']) ? $params['auth_code'] : '';
  38. $openid = isset($params['openid']) ? $params['openid'] : '';
  39. $request = request();
  40. $notifyurl = isset($params['notifyurl']) ? $params['notifyurl'] : $request->root(true) . '/addons/epay/index/' . $type . 'notify';
  41. $returnurl = isset($params['returnurl']) ? $params['returnurl'] : $request->root(true) . '/addons/epay/index/' . $type . 'return/out_trade_no/' . $orderid;
  42. $html = '';
  43. $config = Service::getConfig($type);
  44. $config[$type]['notify_url'] = $notifyurl;
  45. $config[$type]['return_url'] = $returnurl;
  46. if ($type == 'alipay') {
  47. //创建支付对象
  48. $pay = new Pay($config);
  49. //支付宝支付,请根据你的需求,仅选择你所需要的即可
  50. $params = [
  51. 'out_trade_no' => $orderid,//你的订单号
  52. 'total_amount' => $amount,//单位元
  53. 'subject' => $title,
  54. ];
  55. //如果是移动端自动切换为wap
  56. $method = $request->isMobile() ? 'wap' : $method;
  57. switch ($method) {
  58. case 'web':
  59. //电脑支付,跳转
  60. $html = $pay->driver($type)->gateway('web')->pay($params);
  61. Response::create($html)->send();
  62. break;
  63. case 'wap':
  64. //手机网页支付,跳转
  65. $html = $pay->driver($type)->gateway('wap')->pay($params);
  66. Response::create($html)->send();
  67. break;
  68. case 'app':
  69. //APP支付,直接返回字符串
  70. $html = $pay->driver($type)->gateway('app')->pay($params);
  71. break;
  72. case 'scan':
  73. //扫码支付,直接返回字符串
  74. $html = $pay->driver($type)->gateway('scan')->pay($params);
  75. break;
  76. case 'pos':
  77. //刷卡支付,直接返回字符串
  78. //刷卡支付必须要有auth_code
  79. $params['auth_code'] = $auth_code;
  80. $html = $pay->driver($type)->gateway('pos')->pay($params);
  81. break;
  82. default:
  83. //其它支付类型请参考:https://docs.pay.yansongda.cn/alipay
  84. }
  85. } else {
  86. //如果是PC支付,判断当前环境,进行跳转
  87. if ($method == 'web') {
  88. if ((strpos($request->server('HTTP_USER_AGENT'), 'MicroMessenger') !== false)) {
  89. Session::delete("openid");
  90. Session::set("wechatorderdata", $params);
  91. $url = addon_url('epay/api/wechat', [], true, true);
  92. $result = [
  93. "trade_type"=>"MWEB",
  94. "mweb_url"=>$url
  95. ];
  96. return json_encode($result);
  97. } elseif ($request->isMobile()) {
  98. $method = 'wap';
  99. }
  100. }
  101. //创建支付对象
  102. $pay = new Pay($config);
  103. $params = [
  104. 'out_trade_no' => $orderid,//你的订单号
  105. 'body' => $title,
  106. 'total_fee' => $amount * 100, //单位分
  107. ];
  108. switch ($method) {
  109. case 'web':
  110. //电脑支付,跳转到自定义展示页面(FastAdmin独有)
  111. $html = $pay->driver($type)->gateway('web')->pay($params);
  112. Response::create($html)->send();
  113. break;
  114. case 'mp':
  115. //公众号支付
  116. //公众号支付必须有openid
  117. $params['openid'] = $openid;
  118. $html = $pay->driver($type)->gateway('mp')->pay($params);
  119. break;
  120. case 'wap':
  121. //手机网页支付,跳转
  122. $params['spbill_create_ip'] = $request->ip(0, false);
  123. $html = $pay->driver($type)->gateway('wap')->pay($params);
  124. $result = [
  125. "trade_type"=>"MWEB",
  126. "mweb_url"=>$html
  127. ];
  128. return json_encode($result);
  129. break;
  130. case 'app':
  131. //APP支付,直接返回字符串
  132. $html = $pay->driver($type)->gateway('app')->pay($params);
  133. break;
  134. case 'scan':
  135. //扫码支付,直接返回字符串
  136. $html = $pay->driver($type)->gateway('scan')->pay($params);
  137. break;
  138. case 'pos':
  139. //刷卡支付,直接返回字符串
  140. //刷卡支付必须要有auth_code
  141. $params['auth_code'] = $auth_code;
  142. $html = $pay->driver($type)->gateway('pos')->pay($params);
  143. break;
  144. case 'miniapp':
  145. //小程序支付,直接返回字符串
  146. //小程序支付必须要有openid
  147. $params['openid'] = $openid;
  148. $html = $pay->driver($type)->gateway('miniapp')->pay($params);
  149. break;
  150. default:
  151. }
  152. }
  153. //返回字符串
  154. $html = is_array($html) ? json_encode($html) : $html;
  155. return $html;
  156. }
  157. /**
  158. * @param string $orderNo 订单号
  159. * @param string $type 支付类型 wechat alipay
  160. * @param int $amount 退款金额
  161. */
  162. public static function refund($orderNo,$type,$amount){
  163. $config = Service::getConfig($type);
  164. $pay = new Pay($config);
  165. if ($type == "alipay") {
  166. $config_biz = [
  167. 'out_trade_no' => $orderNo,
  168. 'refund_amount' => $amount,
  169. ];
  170. $pay->driver($type)->gateway()->refund($config_biz);
  171. } else {
  172. $config_biz = [
  173. 'out_trade_no' => $orderNo,
  174. 'out_refund_no' => $orderNo,
  175. 'total_fee' => bcmul($amount, 100),
  176. 'refund_fee' => bcmul($amount, 100),
  177. ];
  178. $pay->driver($type)->gateway()->refund($config_biz);
  179. }
  180. }
  181. /**
  182. * 创建支付对象
  183. * @param string $type 支付类型
  184. * @param array $config 配置信息
  185. * @return bool
  186. */
  187. public static function createPay($type, $config = [])
  188. {
  189. $type = strtolower($type);
  190. if (!in_array($type, ['wechat', 'alipay'])) {
  191. return false;
  192. }
  193. $config = self::getConfig($type);
  194. $config = array_merge($config[$type], $config);
  195. $pay = new Pay($config);
  196. return $pay;
  197. }
  198. /**
  199. * 验证回调是否成功
  200. * @param string $type 支付类型
  201. * @param array $config 配置信息
  202. * @return bool|Pay
  203. */
  204. public static function checkNotify($type, $config = [])
  205. {
  206. $type = strtolower($type);
  207. if (!in_array($type, ['wechat', 'alipay'])) {
  208. return false;
  209. }
  210. try {
  211. file_put_contents(ROOT_PATH . '/runtime/log/' . date('Ym') ."/".date("d"). '.log', "开始获取参数" . PHP_EOL, FILE_APPEND);
  212. $pay = new Pay(self::getConfig($type));
  213. $data = $type == 'wechat' ? file_get_contents("php://input") : request()->post('', null, 'trim');
  214. file_put_contents(ROOT_PATH . '/runtime/log/' . date('Ym') ."/".date("d"). '.log', json_encode($data) . PHP_EOL, FILE_APPEND);
  215. $data = $pay->driver($type)->gateway()->verify($data);
  216. if ($type == 'alipay') {
  217. if (in_array($data['trade_status'], ['TRADE_SUCCESS', 'TRADE_FINISHED'])) {
  218. return $pay;
  219. }
  220. } else {
  221. return $pay;
  222. }
  223. } catch (Exception $e) {
  224. return false;
  225. }
  226. return false;
  227. }
  228. /**
  229. * 验证返回是否成功
  230. * @param string $type 支付类型
  231. * @param array $config 配置信息
  232. * @return bool|Pay
  233. */
  234. public static function checkReturn($type, $config = [])
  235. {
  236. $type = strtolower($type);
  237. if (!in_array($type, ['wechat', 'alipay'])) {
  238. return false;
  239. }
  240. //微信无需验证
  241. if ($type == 'wechat') {
  242. return true;
  243. }
  244. try {
  245. $pay = new Pay(self::getConfig($type));
  246. $data = $type == 'wechat' ? file_get_contents("php://input") : request()->get('', null, 'trim');
  247. $data = $pay->driver($type)->gateway()->verify($data);
  248. if ($data) {
  249. return $pay;
  250. }
  251. } catch (Exception $e) {
  252. return false;
  253. }
  254. return false;
  255. }
  256. /**
  257. * 获取配置
  258. * @param string $type 支付类型
  259. * @return array|mixed
  260. */
  261. public static function getConfig($type = 'wechat')
  262. {
  263. $config = get_addon_config('epay');
  264. $config = isset($config[$type]) ? $config[$type] : $config['wechat'];
  265. if ($config['log']) {
  266. $config['log'] = [
  267. 'file' => LOG_PATH . '/epaylogs/' . $type . '-' . date("Y-m-d") . '.log',
  268. 'level' => 'debug'
  269. ];
  270. }
  271. if (isset($config['cert_client']) && substr($config['cert_client'], 0, 6) == '/epay/') {
  272. $config['cert_client'] = ADDON_PATH . $config['cert_client'];
  273. }
  274. if (isset($config['cert_key']) && substr($config['cert_key'], 0, 6) == '/epay/') {
  275. $config['cert_key'] = ADDON_PATH . $config['cert_key'];
  276. }
  277. $config['notify_url'] = empty($config['notify_url']) ? addon_url('epay/api/notifyx', [], false) . '/type/' . $type : $config['notify_url'];
  278. $config['notify_url'] = !preg_match("/^(http:\/\/|https:\/\/)/i", $config['notify_url']) ? request()->root(true) . $config['notify_url'] : $config['notify_url'];
  279. $config['return_url'] = empty($config['return_url']) ? addon_url('epay/api/returnx', [], false) . '/type/' . $type : $config['return_url'];
  280. $config['return_url'] = !preg_match("/^(http:\/\/|https:\/\/)/i", $config['return_url']) ? request()->root(true) . $config['return_url'] : $config['return_url'];
  281. return [$type => $config];
  282. }
  283. }