PaymentService.php 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
  4. // +----------------------------------------------------------------------
  5. // | 版权所有 2017~2021 LARAVEL研发中心
  6. // +----------------------------------------------------------------------
  7. // | 官方网站: http://www.laravel.cn
  8. // +----------------------------------------------------------------------
  9. // | Author: laravel开发员 <laravel.qq.com>
  10. // +----------------------------------------------------------------------
  11. namespace App\Services;
  12. use App\Models\AccountLogModel;
  13. use App\Models\MemberModel;
  14. use App\Models\OrderModel;
  15. use App\Models\PaymentModel;
  16. use Illuminate\Support\Facades\DB;
  17. use Yansongda\Pay\Pay;
  18. use Yansongda\Pay\Provider\Wechat;
  19. /**
  20. * 支付-服务类
  21. * @author laravel开发员
  22. * @since 2020/11/11
  23. * Class PaymentService
  24. * @package App\Services\Api
  25. */
  26. class PaymentService extends BaseService
  27. {
  28. protected static $instance = null;
  29. private $config = [];
  30. /**
  31. * 构造函数
  32. * @author laravel开发员
  33. * @since 2020/11/11
  34. * PaymentService constructor.
  35. */
  36. public function __construct()
  37. {
  38. $this->model = new PaymentModel();
  39. }
  40. /**
  41. * 静态入口
  42. * @return static|null
  43. */
  44. public static function make()
  45. {
  46. if (!self::$instance) {
  47. self::$instance = (new static());
  48. }
  49. return self::$instance;
  50. }
  51. /**
  52. * 创建支付
  53. * @param string $scene 场景,vip-VIP会员
  54. * @param int $payType
  55. * @param int $isMin 是否是小程序
  56. * @return false|\Yansongda\Pay\Provider\Alipay|Wechat
  57. */
  58. public function createPay($scene, $payType = 10, $payPt= '')
  59. {
  60. $config = ConfigService::make()->getConfigOptionByGroup(6);
  61. if ($payType == 10) {
  62. $appid = isset($config['wxpay_appid']) ? $config['wxpay_appid'] : '';
  63. $mpAppid = isset($config['wxpay_mp_appid']) ? $config['wxpay_mp_appid'] : '';
  64. $minAppid = isset($config['wxpay_min_appid']) ? $config['wxpay_min_appid'] : '';
  65. $mchid = isset($config['wxpay_mchd']) ? $config['wxpay_mchd'] : '';
  66. $secretV3Key = isset($config['wxpay_key_v3']) ? $config['wxpay_key_v3'] : '';
  67. $secretV2Key = isset($config['wxpay_key_v2']) ? $config['wxpay_key_v2'] : '';
  68. $wxpaySecretCert = isset($config['wxpay_secret_cert']) ? $config['wxpay_secret_cert'] : '';
  69. $wxpayPublicCert = isset($config['wxpay_public_cert']) ? $config['wxpay_public_cert'] : '';
  70. if (empty($appid) || empty($mchid) || empty($secretV3Key)) {
  71. $this->error = 2616;
  72. return false;
  73. }
  74. // 支付参数
  75. $payConfig = config('payment.wechat');
  76. $payConfig['wechat']['default']['mch_id'] = $mchid;
  77. if($payPt == 'min'){
  78. // 小程序支付
  79. $payConfig['wechat']['default']['mini_app_id'] = $minAppid? $minAppid : $appid;
  80. }else if($payPt == 'mp'){
  81. // 公众号
  82. $payConfig['wechat']['default']['mp_app_id'] = $mpAppid? $mpAppid : $appid;
  83. }else{
  84. // APP支付
  85. $payConfig['wechat']['default']['app_id'] = $appid;
  86. }
  87. if($secretV3Key){
  88. $payConfig['wechat']['default']['mch_secret_key'] = $secretV3Key;
  89. }else if($secretV2Key){
  90. $payConfig['wechat']['default']['mch_secret_key_v2'] = $secretV2Key;
  91. }
  92. if ($wxpaySecretCert) {
  93. $payConfig['wechat']['default']['mch_secret_cert'] = $wxpaySecretCert;
  94. }
  95. if ($wxpayPublicCert) {
  96. $payConfig['wechat']['default']['mch_public_cert_path'] = $wxpayPublicCert;
  97. }
  98. //$payConfig['wechat']['default']['notify_url'] = url('/api/notify/' . $scene . '/10');
  99. $payConfig['wechat']['default']['notify_url'] = url(env('APP_URL').'api/notify/' . $scene . '/10');
  100. $this->config = $payConfig;
  101. return Pay::wechat($payConfig);
  102. } else if ($payType == 20) {
  103. $appid = isset($config['alipay_appid']) ? $config['alipay_appid'] : '';
  104. $appSecretCert = isset($config['alipay_secret_cert']) ? $config['alipay_secret_cert'] : '';
  105. $appPublicCert = isset($config['alipay_app_public_cert_path']) ? $config['alipay_app_public_cert_path'] : '';
  106. $alipayPublicCert = isset($config['alipay_public_cert_path']) ? $config['alipay_public_cert_path'] : '';
  107. $alipayRootCert = isset($config['alipay_root_cert_path']) ? $config['alipay_root_cert_path'] : '';
  108. if (empty($appid) || empty($appSecretCert)) {
  109. $this->error = 2619;
  110. return false;
  111. }
  112. // 支付参数
  113. $payConfig = config('payment.alipay');
  114. $payConfig['alipay']['default']['app_id'] = $appid;
  115. $payConfig['alipay']['default']['app_secret_cert'] = $appSecretCert;
  116. if ($appPublicCert) {
  117. $payConfig['alipay']['default']['app_public_cert_path'] = $appPublicCert;
  118. }
  119. if ($alipayPublicCert) {
  120. $payConfig['alipay']['default']['alipay_public_cert_path'] = $alipayPublicCert;
  121. }
  122. if ($alipayRootCert) {
  123. $payConfig['alipay']['default']['alipay_root_cert_path'] = $alipayRootCert;
  124. }
  125. $payConfig['alipay']['default']['notify_url'] = url('/api/notify/' . $scene . '/20');
  126. $this->config = $payConfig;
  127. return Pay::alipay($payConfig);
  128. } else if ($payType == 30) {
  129. return true;
  130. }
  131. return false;
  132. }
  133. /**
  134. * 微信小程序支付
  135. * @param $userInfo
  136. * @param $order
  137. * @param string $scene
  138. * @return false|\Yansongda\Supports\Collection
  139. */
  140. public function minPay($userInfo, $order, $scene = 'pay')
  141. {
  142. $amount = isset($order['pay_money']) ? $order['pay_money'] : 0;
  143. $openid = isset($order['openid']) ? $order['openid'] : '';
  144. if ($amount < 0) {
  145. $this->error = 2615;
  146. return false;
  147. }
  148. if(empty($openid)){
  149. $this->error = 2614;
  150. return false;
  151. }
  152. $outTradeNo = isset($order['order_no']) && $order['order_no'] ? $order['order_no'] : get_order_num('PR');
  153. // 是否调用过支付,是则用新的支付单号
  154. if ($outTradeNo && $this->model->where(['out_trade_no' => $outTradeNo, 'mark' => 1])->value('id')) {
  155. $outTradeNo = $outTradeNo . date('is') . rand(1, 9);
  156. }
  157. $body = isset($order['body']) ? $order['body'] : '';
  158. $payData = [
  159. 'out_trade_no' => $outTradeNo,
  160. 'description' => $body ? $body : '订单支付',
  161. 'amount' => [
  162. 'total' => intval($amount * 100),
  163. 'currency' => 'CNY'
  164. ],
  165. 'payer' => [
  166. 'openid' => $openid,
  167. ],
  168. ];
  169. // 创建支付
  170. try {
  171. $pay = $this->createPay($scene, 10, 'min');
  172. RedisService::set("caches:payments:wechat:{$scene}_{$outTradeNo}", ['order' => $order, 'config' => $this->config], 7200);
  173. if (empty($pay)) {
  174. $this->error = 2616;
  175. return false;
  176. }
  177. $pay = $pay->mini($payData);
  178. } catch (\Exception $exception) {
  179. RedisService::set("caches:payments:wechat:{$scene}_{$outTradeNo}_error", ['order' => $order,'error'=>$exception->getTrace(), 'config' => $this->config], 7200);
  180. $this->error = $exception->getMessage();
  181. return false;
  182. }
  183. if ($pay->package) {
  184. $data = [
  185. 'user_id' => $userInfo['id'],
  186. 'out_trade_no' => $outTradeNo,
  187. 'order_no' => $order['order_no'],
  188. 'params' => json_encode($pay, 256),
  189. 'total_fee' => $amount,
  190. 'pay_type' => 10,
  191. 'create_time' => time(),
  192. 'status' => 2,
  193. 'mark' => 1,
  194. ];
  195. if ($this->model->insertGetId($data)) {
  196. $this->error = 2617;
  197. return $pay;
  198. }
  199. }
  200. $this->error = 2618;
  201. return false;
  202. }
  203. /**
  204. * 微信支付
  205. * @param $userInfo
  206. * @param $order
  207. * @param string $scene
  208. * @return false|\Yansongda\Supports\Collection
  209. */
  210. public function wechatPay($userInfo, $order, $scene = 'pay')
  211. {
  212. $amount = isset($order['pay_money']) ? $order['pay_money'] : 0;
  213. if ($amount < 0) {
  214. $this->error = 2615;
  215. return false;
  216. }
  217. $outTradeNo = isset($order['order_no']) && $order['order_no'] ? $order['order_no'] : get_order_num('PR');
  218. // 是否调用过支付,是则用新的支付单号
  219. if ($outTradeNo && $this->model->where(['out_trade_no' => $outTradeNo, 'mark' => 1])->value('id')) {
  220. $outTradeNo = $outTradeNo . date('is') . rand(1, 9);
  221. }
  222. $body = isset($order['body']) ? $order['body'] : '';
  223. $type = isset($order['type']) ? $order['type'] : 0;
  224. $payData = [
  225. 'out_trade_no' => $outTradeNo,
  226. 'attach' => "order-{$type}",
  227. 'description' => $body ? $body : '订单支付',
  228. 'amount' => [
  229. 'total' => intval($amount * 100),
  230. 'currency' => 'CNY'
  231. ],
  232. ];
  233. // 创建支付
  234. try {
  235. $pay = $this->createPay($scene, 10);
  236. RedisService::set("caches:payments:wechat:{$scene}_{$outTradeNo}", ['order' => $order, 'config' => $this->config], 7200);
  237. if (empty($pay)) {
  238. $this->error = 2616;
  239. return false;
  240. }
  241. $pay = $pay->app($payData);
  242. } catch (\Exception $exception) {
  243. RedisService::set("caches:payments:wechat:{$scene}_{$outTradeNo}_error", ['order' => $order,'error'=>$exception->getTrace(), 'config' => $this->config], 7200);
  244. $this->error = $exception->getMessage();
  245. return false;
  246. }
  247. if ($pay->prepayid) {
  248. $data = [
  249. 'user_id' => $userInfo['id'],
  250. 'out_trade_no' => $outTradeNo,
  251. 'order_no' => $order['order_no'],
  252. 'params' => json_encode($pay, 256),
  253. 'total_fee' => $amount,
  254. 'pay_type' => 10,
  255. 'create_time' => time(),
  256. 'status' => 2,
  257. 'mark' => 1,
  258. ];
  259. if ($this->model->insertGetId($data)) {
  260. $this->error = 2617;
  261. return $pay;
  262. }
  263. }
  264. $this->error = 2618;
  265. return false;
  266. }
  267. /**
  268. * 支付宝支付
  269. * @param $userInfo
  270. * @param $order
  271. * @return bool
  272. */
  273. public function aliPay($userInfo, $order, $scene = 'deposit')
  274. {
  275. $amount = isset($order['pay_money']) ? $order['pay_money'] : 0;
  276. if ($amount < 0) {
  277. $this->error = 2615;
  278. return false;
  279. }
  280. // 是否调用过支付,是则用新的支付单号
  281. $outTradeNo = isset($order['order_no']) && $order['order_no'] ? $order['order_no'] : get_order_num('PY');
  282. if ($outTradeNo && $this->model->where(['out_trade_no' => $outTradeNo, 'mark' => 1])->value('id')) {
  283. $outTradeNo = $outTradeNo . date('is') . rand(1, 9);
  284. }
  285. $body = isset($order['body']) ? $order['body'] : '';
  286. $payData = [
  287. 'out_trade_no' => $outTradeNo,
  288. 'subject' => $body ? $body : '订单支付',
  289. 'total_amount' => $amount,
  290. ];
  291. // 创建支付
  292. $pay = $this->createPay($scene, 20);
  293. RedisService::set("caches:payments:alipay:{$scene}_{$outTradeNo}", ['order' => $order, 'config' => $this->config], 7200);
  294. if (empty($pay)) {
  295. $this->error = 2619;
  296. return false;
  297. }
  298. $pay = $pay->app($payData);
  299. if ($pay->getStatusCode() == 200) {
  300. $data = [
  301. 'user_id' => $userInfo['id'],
  302. 'out_trade_no' => $outTradeNo,
  303. 'order_no' => $order['order_no'],
  304. 'params' => json_encode($pay, 256),
  305. 'total_fee' => $amount,
  306. 'pay_type' => 20,
  307. 'create_time' => time(),
  308. 'status' => 2,
  309. 'mark' => 1,
  310. ];
  311. if ($this->model->insertGetId($data)) {
  312. $this->error = 2620;
  313. return $pay->getBody()->getContents();
  314. }
  315. }
  316. $this->error = 2621;
  317. return false;
  318. }
  319. /**
  320. * 订单支付回调处理
  321. * @param string $scene 场景 deposit-保证金,depositRefund-保证金退款,withdraw-收入提现
  322. * @param int $payType 支付方式,10-微信支付,20-支付宝支付
  323. * @param array $data 回调数据
  324. * @return bool
  325. */
  326. public function catchNotify($scene, $payType, $data)
  327. {
  328. $outTradeNo = '';
  329. $payTotal = 0;
  330. $transactionId = '';
  331. $payAt = '';
  332. $notifyData = [];
  333. try {
  334. // 微信支付
  335. if ($payType == 10) {
  336. $resource = isset($data['resource']) ? $data['resource'] : [];
  337. $ciphertext = isset($resource['ciphertext']) ? $resource['ciphertext'] : [];
  338. $tradeStatus = isset($ciphertext['trade_state']) ? $ciphertext['trade_state'] : '';
  339. if ($tradeStatus != 'SUCCESS') {
  340. $this->error = 2622;
  341. return false;
  342. }
  343. $outTradeNo = isset($ciphertext['out_trade_no']) ? $ciphertext['out_trade_no'] : '';
  344. $transactionId = isset($ciphertext['transaction_id']) ? $ciphertext['transaction_id'] : '';
  345. if (empty($outTradeNo)) {
  346. $this->error = 2623;
  347. return false;
  348. }
  349. $payAt = isset($ciphertext['success_time']) ? date('Y-m-d H:i:s', strtotime($ciphertext['success_time'])) : date('Y-m-d H:i:s');
  350. $amount = isset($ciphertext['amount']) ? $ciphertext['amount'] : [];
  351. $payTotal = isset($amount['total']) ? moneyFormat($amount['total'] / 100, 3) : 0;
  352. $notifyData = $ciphertext;
  353. if ($payTotal <= 0) {
  354. $this->error = 2624;
  355. return false;
  356. }
  357. } // 支付宝支付
  358. else if ($payType == 20) {
  359. // TRADE_SUCCESS
  360. $tradeStatus = isset($data['trade_status']) ? $data['trade_status'] : '';
  361. if ($tradeStatus != 'TRADE_SUCCESS' && $tradeStatus != 'TRADE_FINISHED') {
  362. $this->error = 2622;
  363. return false;
  364. }
  365. $outTradeNo = isset($data['out_trade_no']) ? $data['out_trade_no'] : '';
  366. if (empty($outTradeNo)) {
  367. $this->error = 2623;
  368. return false;
  369. }
  370. $payTotal = isset($data['total_amount']) ? floatval($data['total_amount']) : 0;
  371. $transactionId = isset($data['trade_no']) ? trim($data['trade_no']) : '';
  372. $payAt = isset($data['send_pay_date']) ? trim($data['send_pay_date']) : date('Y-m-d H:i:s');
  373. $notifyData = $data;
  374. if ($payTotal <= 0) {
  375. $this->error = 2624;
  376. return false;
  377. }
  378. }
  379. // 支付信息
  380. $paymentInfo = $this->model->with(['user'])->where(['out_trade_no' => $outTradeNo, 'mark' => 1])
  381. ->select(['user_id', 'order_no', 'pay_type', 'total_fee', 'status'])
  382. ->first();
  383. $status = isset($paymentInfo['status']) ? $paymentInfo['status'] : 0;
  384. $totalFee = isset($paymentInfo['total_fee']) ? $paymentInfo['total_fee'] : 0;
  385. $paymentPayType = isset($paymentInfo['pay_type']) ? $paymentInfo['pay_type'] : 0;
  386. $orderType = isset($paymentInfo['order_type']) ? $paymentInfo['order_type'] : 0;
  387. $orderNo = isset($paymentInfo['order_no']) ? $paymentInfo['order_no'] : '';
  388. $payUserId = isset($paymentInfo['user_id']) ? $paymentInfo['user_id'] : 0;
  389. if (empty($paymentInfo) || empty($orderNo) || $payUserId <= 0) {
  390. $this->error = 2625;
  391. return false;
  392. }
  393. // 验证支付状态
  394. if ($status == 1) {
  395. $this->error = 2626;
  396. return false;
  397. }
  398. // 验证支付方式
  399. if ($paymentPayType != $payType) {
  400. $this->error = 2627;
  401. return false;
  402. }
  403. if ($payTotal != $totalFee || $payTotal <= 0) {
  404. $this->error = 2628;
  405. return false;
  406. }
  407. // 删除久远旧记录
  408. $this->model->where(['mark' => 1])->where('create_time', '<=', time() - 60 * 86400)->delete();
  409. // 更新订单数据
  410. DB::beginTransaction();
  411. $updateData = ['transaction_id' => $transactionId, 'result' => json_encode($notifyData, 256), 'pay_at' => $payAt, 'status' => 1, 'update_time' => time()];
  412. if (!$this->model->where(['out_trade_no' => $outTradeNo, 'mark' => 1])->update($updateData)) {
  413. $this->error = 2632;
  414. DB::rollBack();
  415. return false;
  416. }
  417. /* TODO 订单验证和状态处理 */
  418. $orderInfo = [];
  419. // 商城订单支付
  420. if ($scene == 'shop') {
  421. $orderInfo = OrderModel::with(['member'])->where(['order_no' => $orderNo, 'mark' => 1])
  422. ->select(['id as order_id', 'user_id', 'expired_at', 'order_no', 'total as pay_money', 'pay_at as pay_time', 'remark', 'status'])
  423. ->first();
  424. $orderStatus = isset($orderInfo['status']) ? $orderInfo['status'] : 0;
  425. // 验证订单
  426. if (empty($orderInfo)) {
  427. DB::rollBack();
  428. $this->error = 2629;
  429. return false;
  430. }
  431. // 订单状态
  432. if ($orderStatus != 1) {
  433. DB::rollBack();
  434. $this->error = 2630;
  435. return false;
  436. }
  437. $updateData = ['pay_at' => $payAt, 'transaction_id' => $transactionId, 'status' => 2, 'update_time' => time()];
  438. if (!OrderModel::where(['order_no' => $orderNo, 'mark' => 1])->update($updateData)) {
  439. $this->error = 2633;
  440. DB::rollBack();
  441. return false;
  442. }
  443. }
  444. // 退款
  445. else if ($scene == 'refund') {
  446. $orderInfo = OrderModel::where(['order_no' => $orderNo, 'mark' => 1])
  447. ->select(['id as order_id', 'user_id', 'order_no', 'total as pay_money', 'remark','refund_remark', 'pay_at as pay_time', 'refund_status as status'])
  448. ->first();
  449. $refundRemark = isset($orderInfo['refund_remark']) ? $orderInfo['refund_remark'] : 'refund_remark';
  450. $orderStatus = isset($orderInfo['status']) ? $orderInfo['status'] : 0;
  451. // 验证订单
  452. if (empty($orderInfo)) {
  453. DB::rollBack();
  454. $this->error = 2629;
  455. return false;
  456. }
  457. // 订单状态
  458. if ($orderStatus != 2) {
  459. DB::rollBack();
  460. $this->error = 2639;
  461. return false;
  462. }
  463. // 订单打款状态
  464. if ($orderStatus == 1) {
  465. DB::rollBack();
  466. $this->error = 2630;
  467. return false;
  468. }
  469. $updateData = ['refund_status' => 1,'refund_remark'=>$refundRemark?$refundRemark.' 已退款成功':'已退款成功', 'update_time' => time()];
  470. if (!OrderModel::where(['order_no' => $orderNo, 'mark' => 1])->update($updateData)) {
  471. $this->error = 2633;
  472. DB::rollBack();
  473. return false;
  474. }
  475. }
  476. // TODO 场景业务回调处理
  477. $orderUserId = isset($orderInfo['user_id']) ? $orderInfo['user_id'] : 0;
  478. RedisService::set("caches:payments:notify_{$scene}:catch_{$orderNo}_{$orderUserId}", ['order' => $orderInfo, 'notify' => $data], 7200);
  479. switch ($scene) {
  480. case 'shop': //
  481. break;
  482. default:
  483. break;
  484. }
  485. $this->error = 2638;
  486. DB::commit();
  487. return true;
  488. } catch (\Exception $exception){
  489. $this->error = $exception->getMessage();
  490. RedisService::set("caches:payments:notify_{$scene}:catch_" . $orderNo.'_error', ['notify' => $data,'error' => $exception->getMessage(),'trace'=>$exception->getTrace()], 7200);
  491. return false;
  492. }
  493. }
  494. /**
  495. * 退款请求
  496. * @param $order
  497. * @param string $scene
  498. * @return bool
  499. * @throws \Yansongda\Pay\Exception\ContainerException
  500. * @throws \Yansongda\Pay\Exception\InvalidParamsException
  501. * @throws \Yansongda\Pay\Exception\ServiceNotFoundException
  502. */
  503. public function refund($order, $scene='vip')
  504. {
  505. $money = isset($order['money'])? $order['money'] : 0;
  506. $payType = isset($order['pay_type'])? $order['pay_type'] : 0;
  507. $orderNo = isset($order['order_no'])? $order['order_no'] : '';
  508. $outTradeNo = isset($order['out_trade_no'])? $order['out_trade_no'] : '';
  509. $transactionId = isset($order['transaction_id'])? $order['transaction_id'] : '';
  510. $remark = isset($order['remark']) && $order['remark']? $order['remark'] : '退款';
  511. $pay = PaymentService::make()->createPay($scene, $payType);
  512. if (empty($pay)) {
  513. DB::rollBack();
  514. $this->error = 2171;
  515. return false;
  516. }
  517. // 保证金退款处理
  518. $refundStatus = false;
  519. switch ($payType) {
  520. case 10: // 微信支付
  521. $data = [
  522. 'out_trade_no' => $outTradeNo,
  523. 'out_refund_no' => get_order_num('RF'),
  524. 'transaction_id' => $transactionId,
  525. 'notify_url' => url("/api/notify/{$scene}/{$payType}"),
  526. 'reason' => $remark,
  527. 'amount' => [
  528. 'refund' => intval($money * 100),
  529. 'total' => intval($money * 100),
  530. 'currency' => 'CNY',
  531. ],
  532. ];
  533. // 请求退款
  534. $pay = $pay->refund($data);
  535. RedisService::set("caches:refunds:order:{$orderNo}_wxpay", ['data' => $data,'pay'=>$pay, 'type' => $payType, 'date' => date('Y-m-d H:i:s')], 7200);
  536. if ($pay->status == 'SUCCESS' || $pay->status == 'PROCESSING') {
  537. $refundStatus = true;
  538. } else {
  539. DB::rollBack();
  540. $this->error = 2172;
  541. return false;
  542. }
  543. break;
  544. case 20: // 支付宝
  545. $data = [
  546. 'out_request_no' => $outTradeNo,
  547. 'trade_no' => $transactionId,
  548. 'refund_amount' => $money,
  549. 'query_options' => ['deposit_back_info'],
  550. 'refund_reason' => $remark,
  551. ];
  552. $payResult = $pay->refund($data);
  553. RedisService::set("caches:refunds:order:{$orderNo}_alipay", ['data' => $data,'pay'=>$payResult, 'type' => $payType, 'date' => date('Y-m-d H:i:s')], 7200);
  554. if ($payResult->code == 10000 || intval($payResult->code) == 40004) {
  555. $refundStatus = true;
  556. } else {
  557. $this->error = 2173;
  558. return false;
  559. }
  560. break;
  561. default:
  562. $this->error = 2179;
  563. return false;
  564. }
  565. $this->error = 2176;
  566. return $refundStatus;
  567. }
  568. }