PayService.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | Think.Admin
  4. // +----------------------------------------------------------------------
  5. // | 版权所有 2014~2017 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
  6. // +----------------------------------------------------------------------
  7. // | 官方网站: http://think.ctolog.com
  8. // +----------------------------------------------------------------------
  9. // | 开源协议 ( https://mit-license.org )
  10. // +----------------------------------------------------------------------
  11. // | github开源项目:https://github.com/zoujingli/Think.Admin
  12. // +----------------------------------------------------------------------
  13. namespace service;
  14. use Endroid\QrCode\QrCode;
  15. use Wechat\WechatPay;
  16. use think\Log;
  17. use think\Db;
  18. /**
  19. * 支付数据服务
  20. * Class PayService
  21. * @package service
  22. * @author Anyon <zoujingli@qq.com>
  23. * @date 2016/10/25 14:49
  24. */
  25. class PayService
  26. {
  27. /**
  28. * 查询订单是否已经支付
  29. * @param string $order_no
  30. * @return bool
  31. */
  32. public static function isPay($order_no)
  33. {
  34. $map = ['order_no' => $order_no, 'is_pay' => '1'];
  35. return Db::name('WechatPayPrepayid')->where($map)->count() > 0;
  36. }
  37. /**
  38. * 创建微信二维码支付(扫码支付模式二)
  39. * @param WechatPay $pay 支付SDK
  40. * @param string $order_no 系统订单号
  41. * @param int $fee 支付金额
  42. * @param string $title 订单标题
  43. * @param string $from 订单来源
  44. * @return false|string
  45. */
  46. public static function createWechatPayQrc(WechatPay $pay, $order_no, $fee, $title, $from = 'wechat')
  47. {
  48. $prepayid = self::createWechatPrepayid($pay, null, $order_no, $fee, $title, 'NATIVE', $from);
  49. if ($prepayid === false) {
  50. return false;
  51. }
  52. $filename = FileService::getFileName($prepayid, 'png', 'qrc/');
  53. if (!FileService::hasFile($filename, 'local')) {
  54. $qrCode = new QrCode($prepayid);
  55. if (null === FileService::save($filename, $qrCode->get(), 'local')) {
  56. return false;
  57. }
  58. }
  59. return FileService::getFileUrl($filename, 'local');
  60. }
  61. /**
  62. * 创建微信JSAPI支付签名包
  63. * @param WechatPay $pay 支付SDK
  64. * @param string $openid 微信用户openid
  65. * @param string $order_no 系统订单号
  66. * @param int $fee 支付金额
  67. * @param string $title 订单标题
  68. * @return bool|array
  69. */
  70. public static function createWechatPayJsPicker(WechatPay $pay, $openid, $order_no, $fee, $title)
  71. {
  72. if (($prepayid = self::createWechatPrepayid($pay, $openid, $order_no, $fee, $title, 'JSAPI')) === false) {
  73. return false;
  74. }
  75. return $pay->createMchPay($prepayid);
  76. }
  77. /**
  78. * 微信退款操作
  79. * @param WechatPay $pay 支付SDK
  80. * @param string $order_no 系统订单号
  81. * @param int $fee 退款金额
  82. * @param string|null $refund_no 退款订单号
  83. * @param string $refund_account
  84. * @return bool
  85. */
  86. public static function putWechatRefund(WechatPay $pay, $order_no, $fee = 0, $refund_no = null, $refund_account = '')
  87. {
  88. $map = ['order_no' => $order_no, 'is_pay' => '1', 'appid' => $pay->appid];
  89. $notify = Db::name('WechatPayPrepayid')->where($map)->find();
  90. if (empty($notify)) {
  91. Log::error("内部订单号{$order_no}验证退款失败");
  92. return false;
  93. }
  94. if (false !== $pay->refund($notify['out_trade_no'], $notify['transaction_id'], is_null($refund_no) ? "T{$order_no}" : $refund_no, $notify['fee'], empty($fee) ? $notify['fee'] : $fee, '', $refund_account)) {
  95. $data = ['out_trade_no' => $notify['out_trade_no'], 'is_refund' => "1", 'refund_at' => date('Y-m-d H:i:s'), 'expires_in' => time() + 7000];
  96. if (DataService::save('wechat_pay_prepayid', $data, 'out_trade_no')) {
  97. return true;
  98. }
  99. Log::error("内部订单号{$order_no}退款成功,系统更新异常");
  100. return false;
  101. }
  102. Log::error("内部订单号{$order_no}退款失败,{$pay->errMsg}");
  103. return false;
  104. }
  105. /**
  106. * 创建微信预支付码
  107. * @param WechatPay $pay 支付SDK
  108. * @param string $openid 支付者Openid
  109. * @param string $order_no 实际订单号
  110. * @param int $fee 实际订单支付费用
  111. * @param string $title 订单标题
  112. * @param string $trade_type 付款方式
  113. * @param string $from 订单来源
  114. * @return bool|string
  115. */
  116. public static function createWechatPrepayid(WechatPay $pay, $openid, $order_no, $fee, $title, $trade_type = 'JSAPI', $from = 'wechat')
  117. {
  118. $map = ['order_no' => $order_no, 'is_pay' => '1', 'expires_in' => time(), 'appid' => $pay->appid, 'trade_type' => $trade_type];
  119. $where = 'appid=:appid and order_no=:order_no and (is_pay=:is_pay or expires_in>:expires_in) and trade_type=:trade_type';
  120. $prepayinfo = Db::name('WechatPayPrepayid')->where($where, $map)->find();
  121. if (empty($prepayinfo) || empty($prepayinfo['prepayid'])) {
  122. $out_trade_no = DataService::createSequence(18, 'WXPAY-OUTER-NO');
  123. if (!($prepayid = $pay->getPrepayId($openid, $title, $out_trade_no, $fee, url("@wechat/notify", '', true, true), $trade_type))) {
  124. Log::error("内部订单号{$order_no}生成预支付失败,{$pay->errMsg}");
  125. return false;
  126. }
  127. $data = ['prepayid' => $prepayid, 'order_no' => $order_no, 'out_trade_no' => $out_trade_no, 'fee' => $fee, 'trade_type' => $trade_type];
  128. list($data['from'], $data['appid'], $data['expires_in']) = [$from, $pay->getAppid(), time() + 5400];
  129. if (Db::name('WechatPayPrepayid')->insert($data) > 0) {
  130. Log::notice("内部订单号{$order_no}生成预支付成功,{$prepayid}");
  131. return $prepayid;
  132. }
  133. }
  134. return $prepayinfo['prepayid'];
  135. }
  136. }