|
|
@@ -1,205 +1,198 @@
|
|
|
<?php
|
|
|
namespace App\Http\Controllers;
|
|
|
|
|
|
+use App\Http\Models\Coupon;
|
|
|
+use App\Http\Models\CouponLog;
|
|
|
use App\Http\Models\Goods;
|
|
|
-use App\Http\Models\Paypal;
|
|
|
+use App\Http\Models\Order;
|
|
|
+use App\Http\Models\Payment;
|
|
|
+use App\Http\Models\User;
|
|
|
use Illuminate\Http\Request;
|
|
|
use Response;
|
|
|
use Redirect;
|
|
|
use Cache;
|
|
|
use Log;
|
|
|
-
|
|
|
-use PayPal\Api\Amount;
|
|
|
-use PayPal\Api\Details;
|
|
|
-use PayPal\Api\Item;
|
|
|
-use PayPal\Api\ItemList;
|
|
|
-use PayPal\Api\Payer;
|
|
|
-use PayPal\Api\Payment;
|
|
|
-use PayPal\Api\PaymentExecution;
|
|
|
-use PayPal\Api\RedirectUrls;
|
|
|
-use PayPal\Api\Transaction;
|
|
|
-use PayPal\Api\ShippingAddress;
|
|
|
-use PayPal\Rest\ApiContext;
|
|
|
-use PayPal\Auth\OAuthTokenCredential;
|
|
|
+use DB;
|
|
|
|
|
|
class PaymentController extends Controller
|
|
|
{
|
|
|
protected static $config;
|
|
|
- private $apiContext;
|
|
|
+ private $accessToken;
|
|
|
|
|
|
function __construct()
|
|
|
{
|
|
|
self::$config = $this->systemConfig();
|
|
|
-
|
|
|
- $this->apiContext = new ApiContext(
|
|
|
- new OAuthTokenCredential(self::$config['paypal_client_id'], self::$config['paypal_client_secret'])
|
|
|
- );
|
|
|
- $this->apiContext->setConfig([
|
|
|
- 'mode' => 'sandbox',
|
|
|
- 'log.LogEnabled' => true,
|
|
|
- 'log.FileName' => storage_path('logs/paypal.log'),
|
|
|
- 'log.LogLevel' => 'DEBUG', // 测试DEBUG,生产环境INFO
|
|
|
- 'cache.enabled' => true,
|
|
|
- // 'http.CURLOPT_CONNECTTIMEOUT' => 30
|
|
|
- // 'http.headers.PayPal-Partner-Attribution-Id' => '123123123'
|
|
|
- //'log.AdapterFactory' => '\PayPal\Log\DefaultLogFactory' // Factory class implementing \PayPal\Log\PayPalLogFactory
|
|
|
- ]);
|
|
|
+ $this->accessToken = $this->getAccessToken();
|
|
|
}
|
|
|
|
|
|
- // 创建支付
|
|
|
- public function create(Request $request)
|
|
|
+ // 获取accessToken
|
|
|
+ private function getAccessToken()
|
|
|
{
|
|
|
- $oid = $request->get('oid');
|
|
|
- $goods_id = $request->get('goods_id');
|
|
|
- $user = $request->session()->get('user');
|
|
|
-
|
|
|
- // 商品信息
|
|
|
- $goods = Goods::query()->where('id', $goods_id)->first();
|
|
|
- if (!$goods) {
|
|
|
- //TODO:购买商品页需要做判断,出现异常时挂掉
|
|
|
- $request->session()->flash('paypalErrorMsg', '创建支付订单失败:所购服务不存在');
|
|
|
-
|
|
|
- return Redirect::back();
|
|
|
+ if (Cache::has('YZY_TOKEN')) {
|
|
|
+ return Cache::get('YZY_TOKEN')['access_token'];
|
|
|
}
|
|
|
|
|
|
- // 设置支付信息
|
|
|
- $payer = new Payer();
|
|
|
- $payer->setPaymentMethod("paypal");
|
|
|
-
|
|
|
- // 设置所购商品信息,包含名称、数量、SKU、价格
|
|
|
- $item1 = new Item();
|
|
|
- $item1->setName($goods->name)->setCurrency('USD')->setQuantity(1)->setSku($goods->sku)->setPrice($goods->price / 100);
|
|
|
-
|
|
|
- $itemList = new ItemList();
|
|
|
- $itemList->setItems([$item1]);
|
|
|
-
|
|
|
- /*
|
|
|
- // 设定收货地址信息,防止用户自付款时可改
|
|
|
- $address = new ShippingAddress();
|
|
|
- $address->setRecipientName($user['username'])
|
|
|
- ->setLine1('余杭区')
|
|
|
- ->setLine2('文一西路969号西溪园区')
|
|
|
- ->setCity('杭州市')
|
|
|
- ->setState('浙江省')
|
|
|
- ->setPhone('+8613800000000')
|
|
|
- ->setPostalCode('311100')
|
|
|
- ->setCountryCode('CN');
|
|
|
-
|
|
|
- // 商品列表写入设定好的地址信息
|
|
|
- $itemList->setShippingAddress($address);
|
|
|
- */
|
|
|
-
|
|
|
- // 设置单据运费、税费、小计算
|
|
|
- $details = new Details();
|
|
|
- $details->setShipping(0)->setTax(0)->setSubtotal($goods->price / 100);
|
|
|
-
|
|
|
- // 设定单据金额
|
|
|
- $amount = new Amount();
|
|
|
- $amount->setCurrency("USD")->setTotal($goods->price / 100)->setDetails($details);
|
|
|
-
|
|
|
- // 跳转页
|
|
|
- $redirectUrls = new RedirectUrls();
|
|
|
- $redirectUrls->setReturnUrl(url("payment/execute?subtotal=" . $goods->price / 100))->setCancelUrl(url("payment/cancel"));
|
|
|
-
|
|
|
- // 设定交易描述
|
|
|
- $transaction = new Transaction();
|
|
|
- $transaction->setAmount($amount)->setItemList($itemList)->setDescription("购买虚拟服务")->setInvoiceNumber(uniqid());
|
|
|
-
|
|
|
- // 创建支付
|
|
|
- $payment = new Payment();
|
|
|
- $payment->setIntent("sale")->setPayer($payer)->setRedirectUrls($redirectUrls)->setTransactions([$transaction]);
|
|
|
- try {
|
|
|
- $payment->create($this->apiContext);
|
|
|
- } catch (\Exception $ex) {
|
|
|
- Log::error($ex->getMessage());
|
|
|
- Log::error('PayPal授权失败,可能是接口配置错误');
|
|
|
+ $clientId = self::$config['youzan_client_id'];
|
|
|
+ $clientSecret = self::$config['youzan_client_secret'];
|
|
|
|
|
|
- $request->session()->flash('paypalErrorMsg', 'PayPal授权失败,可能是接口配置错误');
|
|
|
+ $type = 'self';
|
|
|
+ $keys['kdt_id'] = self::$config['kdt_id'];
|
|
|
|
|
|
- return Redirect::back();
|
|
|
- }
|
|
|
+ $token = (new \Youzan\Open\Token($clientId, $clientSecret))->getToken($type, $keys);
|
|
|
|
|
|
- // 得到支付授权跳转页(给用户点确认付款用)
|
|
|
- $approvalUrl = $payment->getApprovalLink();
|
|
|
+ Cache::put('YZY_TOKEN', $token, 10000);
|
|
|
|
|
|
- return Redirect::to($approvalUrl);
|
|
|
+ return $token['access_token'];
|
|
|
}
|
|
|
|
|
|
- // 执行支付
|
|
|
- public function execute(Request $request)
|
|
|
+ // 创建支付单
|
|
|
+ public function create(Request $request)
|
|
|
{
|
|
|
- \Log::info('execute_params:' . var_export($request->all(), true));
|
|
|
+ $goods_id = intval($request->get('goods_id'));
|
|
|
+ $coupon_sn = $request->get('coupon_sn');
|
|
|
|
|
|
- $subtotal = $request->get('subtotal');
|
|
|
- $paymentId = $request->get('paymentId');
|
|
|
- $token = $request->get('token');
|
|
|
- $PayerID = $request->get('PayerID');
|
|
|
+ $goods = Goods::query()->where('id', $goods_id)->where('status', 1)->first();
|
|
|
+ if (!$goods) {
|
|
|
+ return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:商品或服务已下架']);
|
|
|
+ }
|
|
|
|
|
|
- if (empty($paymentId) || empty($token) || empty($PayerID)) {
|
|
|
- $request->session()->flash('paypalErrorMsg', '支付回调地址错误');
|
|
|
+ // 判断是否开启有赞云支付
|
|
|
+ if (!self::$config['is_youzan']) {
|
|
|
+ return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:系统并未开启在线支付功能']);
|
|
|
+ }
|
|
|
|
|
|
- return Redirect::to('user/goodsList');
|
|
|
+ // 判断是否存在同个商品的未支付订单
|
|
|
+ $existsOrder = Order::query()->where('goods_id', $goods_id)->where('status', 0)->first();
|
|
|
+ if ($existsOrder) {
|
|
|
+ return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:尚有未支付的订单,请先去支付']);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 使用优惠券
|
|
|
+ if ($coupon_sn) {
|
|
|
+ $coupon = Coupon::query()->where('sn', $coupon_sn)->where('is_del', 0)->where('status', 0)->first();
|
|
|
+ if (!$coupon) {
|
|
|
+ return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:优惠券不存在']);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算实际应支付总价
|
|
|
+ $totalPrice = $coupon->type == 2 ? $goods->price * $coupon->discount : $goods->price - $coupon->amount;
|
|
|
+ $totalPrice = $totalPrice > 0 ? $totalPrice : 0;
|
|
|
} else {
|
|
|
- // 根据支付单据获取支付信息
|
|
|
- $payment = Payment::get($paymentId, $this->apiContext);
|
|
|
+ $totalPrice = $goods->price;
|
|
|
+ }
|
|
|
|
|
|
- $details = new Details();
|
|
|
- $details->setShipping(0)->setTax(0)->setSubtotal($subtotal);
|
|
|
+ DB::beginTransaction();
|
|
|
+ try {
|
|
|
+ $user = $request->session()->get('user');
|
|
|
+ $orderId = date('ymdHis') . mt_rand(100000, 999999);
|
|
|
+ $sn = makeRandStr(12);
|
|
|
+
|
|
|
+ // 生成订单
|
|
|
+ $order = new Order();
|
|
|
+ $order->orderId = $orderId;
|
|
|
+ $order->user_id = $user['id'];
|
|
|
+ $order->goods_id = $goods_id;
|
|
|
+ $order->coupon_id = !empty($coupon) ? $coupon->id : 0;
|
|
|
+ $order->totalOriginalPrice = $goods->price;
|
|
|
+ $order->totalPrice = $totalPrice;
|
|
|
+ $order->expire_at = date("Y-m-d H:i:s", strtotime("+" . $goods->days . " days"));
|
|
|
+ $order->is_expire = 0;
|
|
|
+ $order->pay_way = 2;
|
|
|
+ $order->status = 0;
|
|
|
+ $order->save();
|
|
|
+
|
|
|
+ // 生成支付单
|
|
|
+ $client = new \Youzan\Open\Client($this->accessToken);
|
|
|
+
|
|
|
+ $method = 'youzan.pay.qrcode.create';
|
|
|
+ $apiVersion = '3.0.0';
|
|
|
+
|
|
|
+ $params = [
|
|
|
+ 'qr_name' => $goods->name, // 商品名
|
|
|
+ 'qr_price' => $totalPrice, // 单位分
|
|
|
+ 'qr_source' => $orderId, // 本地订单号
|
|
|
+ 'qr_type' => 'QR_TYPE_DYNAMIC'
|
|
|
+ ];
|
|
|
+
|
|
|
+ $result = $client->get($method, $apiVersion, $params);
|
|
|
+ if (isset($result['error_response'])) {
|
|
|
+ Log::error('【有赞云】创建二维码失败:' . $result['error_response']['msg']);
|
|
|
+
|
|
|
+ throw new \Exception($result['error_response']['msg']);
|
|
|
+ }
|
|
|
|
|
|
- $amount = new Amount();
|
|
|
- $amount->setCurrency('USD')->setTotal($subtotal)->setDetails($details);
|
|
|
+ $payment = new Payment();
|
|
|
+ $payment->sn = $sn;
|
|
|
+ $payment->user_id = $user['id'];
|
|
|
+ $payment->oid = $order->oid;
|
|
|
+ $payment->orderId = $orderId;
|
|
|
+ $payment->pay_way = 1;
|
|
|
+ $payment->amount = $order->totalPrice;
|
|
|
+ $payment->qr_id = $result['response']['qr_id'];
|
|
|
+ $payment->qr_url = $result['response']['qr_url'];
|
|
|
+ $payment->qr_code = $result['response']['qr_code'];
|
|
|
+ $payment->status = 0;
|
|
|
+ $payment->save();
|
|
|
|
|
|
- $transaction = new Transaction();
|
|
|
- $transaction->setAmount($amount);
|
|
|
+ DB::commit();
|
|
|
|
|
|
- // 执行支付
|
|
|
- $execution = new PaymentExecution();
|
|
|
- $execution->setPayerId($PayerID)->addTransaction($transaction);
|
|
|
+ return Response::json(['status' => 'success', 'data' => $sn, 'message' => '创建支付单成功']);
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ DB::rollBack();
|
|
|
|
|
|
- try {
|
|
|
- $result = $payment->execute($execution, $this->apiContext);
|
|
|
- \Log::info(var_export($result, true));
|
|
|
+ Log::error('创建支付订单失败:' . $e->getMessage());
|
|
|
|
|
|
- // 支付成功,写入支付单据信息
|
|
|
+ return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:' . $e->getMessage()]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 支付单详情
|
|
|
+ public function detail(Request $request, $sn)
|
|
|
+ {
|
|
|
+ if (empty($sn)) {
|
|
|
+ return Redirect::to('user/goodsList');
|
|
|
+ }
|
|
|
|
|
|
+ $user = $request->session()->get('user');
|
|
|
|
|
|
- } catch (\Exception $ex) {
|
|
|
- var_dump($ex);
|
|
|
- echo "支付失败";
|
|
|
- exit(1);
|
|
|
- }
|
|
|
+ $payment = Payment::query()->with(['order', 'order.goods'])->where('sn', $sn)->where('user_id', $user['id'])->first();
|
|
|
+ if (!$payment) {
|
|
|
+ return Redirect::to('user/goodsList');
|
|
|
+ }
|
|
|
|
|
|
- \Log::info(var_export($payment, true));
|
|
|
+ $order = Order::query()->where('oid', $payment->oid)->first();
|
|
|
+ if (!$order) {
|
|
|
+ $request->session()->flash('errorMsg', '订单不存在');
|
|
|
|
|
|
- return $payment;
|
|
|
+ return Response::view('payment/' . $sn);
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- // 取消支付
|
|
|
- public function cancel(Request $request)
|
|
|
- {
|
|
|
- var_dump($request->all());
|
|
|
+ $view['payment'] = $payment;
|
|
|
|
|
|
- echo '取消支付';
|
|
|
+ return Response::view('payment/detail', $view);
|
|
|
}
|
|
|
|
|
|
- // 查询支付状态
|
|
|
- public function query()
|
|
|
+ // 获取订单支付状态
|
|
|
+ public function getStatus(Request $request)
|
|
|
{
|
|
|
+ $sn = $request->get('sn');
|
|
|
|
|
|
- }
|
|
|
+ if (empty($sn)) {
|
|
|
+ return Response::json(['status' => 'fail', 'data' => '', 'message' => '请求失败']);
|
|
|
+ }
|
|
|
|
|
|
- // 写入日志
|
|
|
- private function log($oid, $invoice_number = '', $items = '', $response_data = '', $error = '')
|
|
|
- {
|
|
|
- $paypal = new Paypal();
|
|
|
- $paypal->oid = $oid;
|
|
|
- $paypal->invoice_number = $invoice_number;
|
|
|
- $paypal->items = $items;
|
|
|
- $paypal->response_data = $response_data;
|
|
|
- $paypal->error = $error;
|
|
|
- $paypal->save();
|
|
|
-
|
|
|
- return $paypal->id;
|
|
|
+ $user = $request->session()->get('user');
|
|
|
+ $payment = Payment::query()->where('sn', $sn)->where('user_id', $user['id'])->first();
|
|
|
+ if (!$payment) {
|
|
|
+ return Response::json(['status' => 'fail', 'data' => '', 'message' => '支付失败']);
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($payment->status) {
|
|
|
+ return Response::json(['status' => 'success', 'data' => '', 'message' => '支付成功']);
|
|
|
+ } else if ($payment->status < 0) {
|
|
|
+ return Response::json(['status' => 'fail', 'data' => '', 'message' => '支付失败']);
|
|
|
+ } else {
|
|
|
+ return Response::json(['status' => 'fail', 'data' => '', 'message' => '等待支付']);
|
|
|
+ }
|
|
|
}
|
|
|
}
|