PaymentController.php 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. <?php
  2. namespace App\Http\Controllers;
  3. use App\Http\Models\Coupon;
  4. use App\Http\Models\Goods;
  5. use App\Http\Models\Order;
  6. use App\Http\Models\Payment;
  7. use App\Http\Models\PaymentCallback;
  8. use Illuminate\Http\Request;
  9. use Response;
  10. use Redirect;
  11. use Cache;
  12. use Log;
  13. use DB;
  14. class PaymentController extends Controller
  15. {
  16. protected static $config;
  17. private $accessToken;
  18. function __construct()
  19. {
  20. self::$config = $this->systemConfig();
  21. $this->accessToken = $this->getAccessToken();
  22. }
  23. // 获取accessToken
  24. private function getAccessToken()
  25. {
  26. if (Cache::has('YZY_TOKEN')) {
  27. $yzyToken = Cache::get('YZY_TOKEN');
  28. if (isset($yzyToken['error'])) { // 错误兼容
  29. Cache::forget('YZY_TOKEN');
  30. } else {
  31. return Cache::get('YZY_TOKEN')['access_token'];
  32. }
  33. }
  34. $clientId = self::$config['youzan_client_id'];
  35. $clientSecret = self::$config['youzan_client_secret'];
  36. $type = 'self';
  37. $keys['kdt_id'] = self::$config['kdt_id'];
  38. $token = (new \Youzan\Open\Token($clientId, $clientSecret))->getToken($type, $keys);
  39. if (isset($token['error'])) {
  40. Log::info('获取有赞云支付access_token失败:' . $token['error_description']);
  41. return '';
  42. } else {
  43. Cache::put('YZY_TOKEN', $token, 10000);
  44. return $token['access_token'];
  45. }
  46. }
  47. // 创建支付单
  48. public function create(Request $request)
  49. {
  50. $goods_id = intval($request->get('goods_id'));
  51. $coupon_sn = $request->get('coupon_sn');
  52. $goods = Goods::query()->where('id', $goods_id)->where('status', 1)->first();
  53. if (!$goods) {
  54. return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:商品或服务已下架']);
  55. }
  56. // 判断是否开启有赞云支付
  57. if (!self::$config['is_youzan']) {
  58. return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:系统并未开启在线支付功能']);
  59. }
  60. // 判断是否存在同个商品的未支付订单
  61. $existsOrder = Order::query()->where('goods_id', $goods_id)->where('status', 0)->first();
  62. if ($existsOrder) {
  63. return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:尚有未支付的订单,请先去支付']);
  64. }
  65. // 使用优惠券
  66. if ($coupon_sn) {
  67. $coupon = Coupon::query()->where('sn', $coupon_sn)->where('is_del', 0)->where('status', 0)->first();
  68. if (!$coupon) {
  69. return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:优惠券不存在']);
  70. }
  71. // 计算实际应支付总价
  72. $totalPrice = $coupon->type == 2 ? $goods->price * $coupon->discount : $goods->price - $coupon->amount;
  73. $totalPrice = $totalPrice > 0 ? $totalPrice : 0;
  74. } else {
  75. $totalPrice = $goods->price;
  76. }
  77. DB::beginTransaction();
  78. try {
  79. $user = $request->session()->get('user');
  80. $orderId = date('ymdHis') . mt_rand(100000, 999999);
  81. $sn = makeRandStr(12);
  82. // 生成订单
  83. $order = new Order();
  84. $order->orderId = $orderId;
  85. $order->user_id = $user['id'];
  86. $order->goods_id = $goods_id;
  87. $order->coupon_id = !empty($coupon) ? $coupon->id : 0;
  88. $order->totalOriginalPrice = $goods->price;
  89. $order->totalPrice = $totalPrice;
  90. $order->expire_at = date("Y-m-d H:i:s", strtotime("+" . $goods->days . " days"));
  91. $order->is_expire = 0;
  92. $order->pay_way = 2;
  93. $order->status = 0;
  94. $order->save();
  95. // 生成支付单
  96. $client = new \Youzan\Open\Client($this->accessToken);
  97. $method = 'youzan.pay.qrcode.create';
  98. $apiVersion = '3.0.0';
  99. $params = [
  100. 'qr_name' => $goods->name, // 商品名
  101. 'qr_price' => $totalPrice, // 单位分
  102. 'qr_source' => $orderId, // 本地订单号
  103. 'qr_type' => 'QR_TYPE_DYNAMIC'
  104. ];
  105. $result = $client->get($method, $apiVersion, $params);
  106. if (isset($result['error_response'])) {
  107. Log::error('【有赞云】创建二维码失败:' . $result['error_response']['msg']);
  108. throw new \Exception($result['error_response']['msg']);
  109. }
  110. $payment = new Payment();
  111. $payment->sn = $sn;
  112. $payment->user_id = $user['id'];
  113. $payment->oid = $order->oid;
  114. $payment->orderId = $orderId;
  115. $payment->pay_way = 1;
  116. $payment->amount = $order->totalPrice;
  117. $payment->qr_id = $result['response']['qr_id'];
  118. $payment->qr_url = $result['response']['qr_url'];
  119. $payment->qr_code = $result['response']['qr_code'];
  120. $payment->status = 0;
  121. $payment->save();
  122. DB::commit();
  123. return Response::json(['status' => 'success', 'data' => $sn, 'message' => '创建支付单成功']);
  124. } catch (\Exception $e) {
  125. DB::rollBack();
  126. Log::error('创建支付订单失败:' . $e->getMessage());
  127. return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:' . $e->getMessage()]);
  128. }
  129. }
  130. // 支付单详情
  131. public function detail(Request $request, $sn)
  132. {
  133. if (empty($sn)) {
  134. return Redirect::to('user/goodsList');
  135. }
  136. $user = $request->session()->get('user');
  137. $payment = Payment::query()->with(['order', 'order.goods'])->where('sn', $sn)->where('user_id', $user['id'])->first();
  138. if (!$payment) {
  139. return Redirect::to('user/goodsList');
  140. }
  141. $order = Order::query()->where('oid', $payment->oid)->first();
  142. if (!$order) {
  143. $request->session()->flash('errorMsg', '订单不存在');
  144. return Response::view('payment/' . $sn);
  145. }
  146. $view['payment'] = $payment;
  147. return Response::view('payment/detail', $view);
  148. }
  149. // 获取订单支付状态
  150. public function getStatus(Request $request)
  151. {
  152. $sn = $request->get('sn');
  153. if (empty($sn)) {
  154. return Response::json(['status' => 'fail', 'data' => '', 'message' => '请求失败']);
  155. }
  156. $user = $request->session()->get('user');
  157. $payment = Payment::query()->where('sn', $sn)->where('user_id', $user['id'])->first();
  158. if (!$payment) {
  159. return Response::json(['status' => 'fail', 'data' => '', 'message' => '支付失败']);
  160. }
  161. if ($payment->status) {
  162. return Response::json(['status' => 'success', 'data' => '', 'message' => '支付成功']);
  163. } else if ($payment->status < 0) {
  164. return Response::json(['status' => 'fail', 'data' => '', 'message' => '支付失败']);
  165. } else {
  166. return Response::json(['status' => 'fail', 'data' => '', 'message' => '等待支付']);
  167. }
  168. }
  169. // 有赞云回调日志
  170. public function callbackList(Request $request)
  171. {
  172. $status = $request->get('status', 0);
  173. $query = PaymentCallback::query();
  174. if ($status) {
  175. $query->where('status', $status);
  176. }
  177. $view['list'] = $query->orderBy('id', 'desc')->paginate(10);
  178. return Response::view('payment/callbackList', $view);
  179. }
  180. }