|
@@ -0,0 +1,338 @@
|
|
|
+<?php namespace App\Http\Controllers\Api;
|
|
|
+
|
|
|
+use App\Models\Custom;
|
|
|
+use App\Models\Orders;
|
|
|
+use App\Facades\Servers\Logs\Log;
|
|
|
+use App\Models\OrdersProduct;
|
|
|
+use App\Models\Regiment;
|
|
|
+use App\Models\RegimentActive;
|
|
|
+use App\Models\RegimentRecord;
|
|
|
+use App\Models\CustomScore;
|
|
|
+use EasyWeChat\Factory;
|
|
|
+use Illuminate\Http\Request;
|
|
|
+use App\Servers\WechatPay\Payment;
|
|
|
+use App\Facades\Servers\WechatMini\Mini;
|
|
|
+use Illuminate\Support\Facades\DB;
|
|
|
+use WeChatPay\Formatter;
|
|
|
+use WeChatPay\Crypto\AesGcm;
|
|
|
+use WeChatPay\Crypto\Rsa;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 微信支付接口
|
|
|
+ *
|
|
|
+ * @author JUN
|
|
|
+ *
|
|
|
+ * */
|
|
|
+class WechatPay extends Api{
|
|
|
+ /**
|
|
|
+ * 小程序微信支付下单 /api/wechat_pay/pay
|
|
|
+ *
|
|
|
+ * */
|
|
|
+ public function pay(Custom $Custom)
|
|
|
+ {
|
|
|
+ // 检查登录
|
|
|
+ $uid = $this->checkLogin();
|
|
|
+ $code = request('code','');
|
|
|
+ $orderId = request('order_id','');
|
|
|
+ $orderInfo = Orders::query()->where('id','=',$orderId)->first()->toArray();
|
|
|
+ if (empty($orderInfo))
|
|
|
+ return json_send(['code'=>'error','msg'=>'订单不存在','data'=>['id'=>null]]);
|
|
|
+ if ($orderInfo['custom_uid'] != $uid)
|
|
|
+ return json_send(['code'=>'error','msg'=>'无权操作','data'=>['id'=>null]]);
|
|
|
+ if ($orderInfo['status'] != 1)
|
|
|
+ return json_send(['code'=>'error','msg'=>'订单已支付或取消','data'=>['id'=>null]]);
|
|
|
+ //获取openid
|
|
|
+ $result = Mini::jscode2session($code);
|
|
|
+ if (!$result['openid']) return json_send(['code'=>'error','msg'=>'获取openid失败','data'=>$result['error']]);
|
|
|
+ $openid = $result['openid'];
|
|
|
+ $description = '开邻智数-订单编号'.$orderInfo['snowflake_id'];
|
|
|
+ $payment = new Payment();
|
|
|
+ return $payment->pay(['out_trade_no' => $orderInfo['snowflake_id'],'openid' => $openid,'description' => $description,'total_price' => $orderInfo['pay_total']]);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 小程序微信支付回调 /api/wechat_pay/notify
|
|
|
+ *
|
|
|
+ * */
|
|
|
+ public function notify(Custom $Custom,CustomScore $CustomScore)
|
|
|
+ {
|
|
|
+ $content = file_get_contents("php://input");
|
|
|
+ if (!empty($content)) {
|
|
|
+ //直接json字符串
|
|
|
+ $params = $content;
|
|
|
+ } elseif (!empty($_POST)) {
|
|
|
+ //直接POST数据
|
|
|
+ $params = $_POST;
|
|
|
+ } else {
|
|
|
+ $params = [];
|
|
|
+ }
|
|
|
+ $post_data = $params;
|
|
|
+ Log::log('notify_wechat_pay', 'post_data:' . $post_data);
|
|
|
+ //获取headers参数
|
|
|
+ $headers = request()->header();
|
|
|
+ Log::log('notify_wechat_pay', '微信支付回调返回headers参数:' . json_encode($headers));
|
|
|
+
|
|
|
+ $inWechatpaySignature = $headers['wechatpay-signature'][0];
|
|
|
+ $inWechatpayTimestamp = $headers['wechatpay-timestamp'][0];
|
|
|
+ $inWechatpaySerial = $headers['wechatpay-serial'][0];
|
|
|
+ $inWechatpayNonce = $headers['wechatpay-nonce'][0];
|
|
|
+ $inBody = $post_data;
|
|
|
+ Log::log('notify_wechat_pay', 'wechatpay-timestamp:' . $inWechatpayTimestamp);
|
|
|
+ $apiv3Key = Config('wechatpay.APIV3');// 在商户平台上设置的APIv3密钥
|
|
|
+ // 根据通知的平台证书序列号,查询本地平台证书文件,
|
|
|
+ $platformCertificateFilePath = Config('wechatpay.platformCertificate');
|
|
|
+ $platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);
|
|
|
+ try {
|
|
|
+ // 检查通知时间偏移量,允许5分钟之内的偏移
|
|
|
+ $timeOffsetStatus = 300 >= abs(Formatter::timestamp() - (int)$inWechatpayTimestamp);
|
|
|
+ Log::log('notify_wechat_pay', '时间偏移量:' . $timeOffsetStatus);
|
|
|
+ $verifiedStatus = Rsa::verify(
|
|
|
+ // 构造验签名串
|
|
|
+ Formatter::joinedByLineFeed($inWechatpayTimestamp, $inWechatpayNonce, $inBody),
|
|
|
+ $inWechatpaySignature,
|
|
|
+ $platformPublicKeyInstance
|
|
|
+ );
|
|
|
+ }catch (\Exception $e){
|
|
|
+ Log::log('notify_wechat_pay', '错误getMessage:' . $e->getMessage());
|
|
|
+ }
|
|
|
+ Log::log('notify_wechat_pay', '验签:' . $verifiedStatus.'验签inWechatpayTimestamp:' . $inWechatpayTimestamp.'验签verifiedStatus:' . $inWechatpayNonce.'验签timeOffsetStatus:' . $timeOffsetStatus);
|
|
|
+ if ($timeOffsetStatus && $verifiedStatus) {
|
|
|
+ // 转换通知的JSON文本消息为PHP Array数组
|
|
|
+ $inBodyArray = (array)json_decode($inBody, true);
|
|
|
+ // 使用PHP7的数据解构语法,从Array中解构并赋值变量
|
|
|
+ ['resource' => [
|
|
|
+ 'ciphertext' => $ciphertext,
|
|
|
+ 'nonce' => $nonce,
|
|
|
+ 'associated_data' => $aad
|
|
|
+ ]] = $inBodyArray;
|
|
|
+ // 加密文本消息解密
|
|
|
+ $inBodyResource = AesGcm::decrypt($ciphertext, $apiv3Key, $nonce, $aad);
|
|
|
+ // 把解密后的文本转换为PHP Array数组
|
|
|
+ $inBodyResourceArray = (array)json_decode($inBodyResource, true);
|
|
|
+ Log::log('notify_wechat_pay', '打印解密后的结果:' . json_encode($inBodyResourceArray));
|
|
|
+ Log::log('notify_wechat_pay', '参数:' . $inBodyResourceArray['trade_state'] . '订单号' . $inBodyResourceArray['out_trade_no'] . '微信支付号' . $inBodyResourceArray['transaction_id']);
|
|
|
+ if ($inBodyResourceArray['trade_state'] == "SUCCESS") {
|
|
|
+ Log::log('notify_wechat_pay', '通知订单');
|
|
|
+ $orderInfo = Orders::query()->where('snowflake_id','=',$inBodyResourceArray['out_trade_no'])->first()->toArray();
|
|
|
+ $status = 2;
|
|
|
+ if ($orderInfo['regiment_id'] > 0){
|
|
|
+ $status = 10;
|
|
|
+ }
|
|
|
+ //更新订单支付状态
|
|
|
+ $orderData = [
|
|
|
+ 'pay_time' => time(),
|
|
|
+ 'transaction_id'=>$inBodyResourceArray['transaction_id'],
|
|
|
+ 'status'=>$status,
|
|
|
+ ];
|
|
|
+ // 组合数据,写入订单表,子表
|
|
|
+ DB::beginTransaction();
|
|
|
+ try {
|
|
|
+ $res = Orders::query()->where('snowflake_id','=',$inBodyResourceArray['out_trade_no'])->update($orderData);
|
|
|
+ Log::log('notify_wechat_pay', '更新订单,snowflake_id:'.$inBodyResourceArray['out_trade_no'].';'. json_encode($res));
|
|
|
+ if (!$res) {
|
|
|
+ // 回退数据
|
|
|
+ DB::rollBack();
|
|
|
+ Log::log('notify_wechat_pay', '更新订单失败' . json_encode($res));
|
|
|
+ return json_send(['code'=>'FAIL']);
|
|
|
+ }
|
|
|
+ //更新子订单
|
|
|
+ $res = OrdersProduct::query()->where('order_id','=',$orderInfo['id'])->update(['status'=>$status]);
|
|
|
+ Log::log('notify_wechat_pay', '更新子订单,order_id:'.$orderInfo['id'].';'. json_encode($res));
|
|
|
+ if (!$res) {
|
|
|
+ Log::log('notify_wechat_pay', '更新子订单失败:'.$orderInfo['id'].':'.$status . json_encode($res));
|
|
|
+ // 回退数据
|
|
|
+ DB::rollBack();
|
|
|
+ return json_send(['code'=>'FAIL']);
|
|
|
+ }
|
|
|
+ //更新团信息
|
|
|
+ if ($orderInfo['regiment_id']){
|
|
|
+ //查询团信息
|
|
|
+ $regimentInfo = Regiment::query()->where('id','=',$orderInfo['regiment_id'])->first()->toArray();
|
|
|
+ if (!$regimentInfo) {
|
|
|
+ Log::log('notify_wechat_pay', '查询团信息失败' . json_encode($regimentInfo));
|
|
|
+ // 回退数据
|
|
|
+ DB::rollBack();
|
|
|
+ return json_send(['code'=>'FAIL']);
|
|
|
+ }
|
|
|
+ //查询团活动
|
|
|
+ $regimentActiveInfo = RegimentActive::query()->where('id','=',$regimentInfo['active_id'])->first();
|
|
|
+ if (!$regimentActiveInfo) {
|
|
|
+ Log::log('notify_wechat_pay', '查询团活动失败' . json_encode($regimentInfo));
|
|
|
+ // 回退数据
|
|
|
+ DB::rollBack();
|
|
|
+ return json_send(['code'=>'FAIL']);
|
|
|
+ }
|
|
|
+ //查询团记录
|
|
|
+ $regimentRecordInfo = RegimentRecord::query()->where('order_id','=',$orderInfo['id'])->first();
|
|
|
+ if (!$regimentRecordInfo) {
|
|
|
+ Log::log('notify_wechat_pay', '查询团记录失败' . json_encode($regimentInfo));
|
|
|
+ // 回退数据
|
|
|
+ DB::rollBack();
|
|
|
+ return json_send(['code'=>'FAIL']);
|
|
|
+ }
|
|
|
+ $regimentId = $orderInfo['regiment_id'];
|
|
|
+ // 拼团人数加1
|
|
|
+ $inc = Regiment::query()->where('id','=',$regimentId)->increment('people_number',1);
|
|
|
+ Log::log('notify_wechat_pay', '拼团人数加1,regiment_id:'.$regimentId.';'. json_encode($inc));
|
|
|
+ if( !$inc ) {
|
|
|
+ Log::log('notify_wechat_pay', '更新团人数加1失败' . json_encode($regimentInfo));
|
|
|
+ // 回退数据
|
|
|
+ DB::rollBack();
|
|
|
+ return json_send(['code'=>'FAIL']);
|
|
|
+ }
|
|
|
+ //团满
|
|
|
+ if ((($regimentInfo['people_number'] + 1) == $regimentActiveInfo['number']) && $regimentActiveInfo['exceed_people'] == 1) {
|
|
|
+ $res = regiment::query()->where('id','=',$regimentId)->update(['status'=>3]);
|
|
|
+ Log::log('notify_wechat_pay', '图满 团状态,regiment_id:'.$regimentId.';'. json_encode($res));
|
|
|
+ if( !$res ) {
|
|
|
+ Log::log('notify_wechat_pay', '更新团订单失败1' . json_encode($regimentInfo));
|
|
|
+ // 回退数据
|
|
|
+ DB::rollBack();
|
|
|
+ return json_send(['code'=>'FAIL']);
|
|
|
+ }
|
|
|
+ //修改团记录状态
|
|
|
+ $res = RegimentRecord::query()->where('order_id','=',$orderInfo['id'])->update(['status'=>3]);
|
|
|
+ if( !$res ) {
|
|
|
+ Log::log('notify_wechat_pay', '更新团记录状态失败' . json_encode($regimentInfo));
|
|
|
+ // 回退数据
|
|
|
+ DB::rollBack();
|
|
|
+ return json_send(['code'=>'FAIL']);
|
|
|
+ }
|
|
|
+ //修改订单
|
|
|
+ $orderRes = Orders::query()->where('regiment_id','=',$regimentId)->update(['status'=>'2']);
|
|
|
+ if( !$orderRes ) {
|
|
|
+ Log::log('notify_wechat_pay', '更新订单失败' . json_encode($regimentInfo));
|
|
|
+ // 回退数据
|
|
|
+ DB::rollBack();
|
|
|
+ return json_send(['code'=>'FAIL']);
|
|
|
+ }
|
|
|
+ //赠送积分
|
|
|
+ $orderList = Orders::query()->where('regiment_id','=',$regimentId)->get();
|
|
|
+ foreach ($orderList as $key => $value) {
|
|
|
+ if( $value['order_score'] > 0 ) $CustomScore->trade($orderInfo['custom_uid'],$value['id'],$value['order_score'],5,1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 提交数据
|
|
|
+ DB::commit();
|
|
|
+ }catch (\Exception $e){
|
|
|
+ Log::log('notify_wechat_pay', '更新订单失败' . json_encode($e));
|
|
|
+ return json_send(['code'=>'FAIL']);
|
|
|
+ }
|
|
|
+ $orderInfo = Orders::query()->where('snowflake_id','=',$inBodyResourceArray['out_trade_no'])->first()->toArray();
|
|
|
+ Log::log('notify_wechat_pay', '支付回调完成 通知返回' . json_encode($orderInfo));
|
|
|
+ return json_send(['code'=>'SUCCESS']);
|
|
|
+
|
|
|
+ }
|
|
|
+ return json_send(['code'=>'SUCCESS']);
|
|
|
+ }else{
|
|
|
+ return json_send(['code'=>'FAIL']);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 小程序微信支付 退款回调 /api/wechat_pay/refund_notify
|
|
|
+ *
|
|
|
+ * */
|
|
|
+ public function refund_notify(Custom $Custom,CustomScore $CustomScore)
|
|
|
+ {
|
|
|
+ $content = file_get_contents("php://input");
|
|
|
+ if (!empty($content)) {
|
|
|
+ //直接json字符串
|
|
|
+ $params = $content;
|
|
|
+ } elseif (!empty($_POST)) {
|
|
|
+ //直接POST数据
|
|
|
+ $params = $_POST;
|
|
|
+ } else {
|
|
|
+ $params = [];
|
|
|
+ }
|
|
|
+ $post_data = $params;
|
|
|
+ Log::log('notify_refund_wechat_pay', 'post_data:' . $post_data);
|
|
|
+ //获取headers参数
|
|
|
+ $headers = request()->header();
|
|
|
+ Log::log('notify_refund_wechat_pay', '微信支付回调返回headers参数:' . json_encode($headers));
|
|
|
+
|
|
|
+ $inWechatpaySignature = $headers['wechatpay-signature'][0];
|
|
|
+ $inWechatpayTimestamp = $headers['wechatpay-timestamp'][0];
|
|
|
+ $inWechatpaySerial = $headers['wechatpay-serial'][0];
|
|
|
+ $inWechatpayNonce = $headers['wechatpay-nonce'][0];
|
|
|
+ $inBody = $post_data;
|
|
|
+ Log::log('notify_refund_wechat_pay', 'wechatpay-timestamp:' . $inWechatpayTimestamp);
|
|
|
+ $apiv3Key = Config('wechatpay.APIV3');// 在商户平台上设置的APIv3密钥
|
|
|
+ // 根据通知的平台证书序列号,查询本地平台证书文件,
|
|
|
+ $platformCertificateFilePath = Config('wechatpay.platformCertificate');
|
|
|
+ $platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);
|
|
|
+ try {
|
|
|
+ // 检查通知时间偏移量,允许5分钟之内的偏移
|
|
|
+ $timeOffsetStatus = 300 >= abs(Formatter::timestamp() - (int)$inWechatpayTimestamp);
|
|
|
+ Log::log('notify_wechat_pay', '时间偏移量:' . $timeOffsetStatus);
|
|
|
+ $verifiedStatus = Rsa::verify(
|
|
|
+ // 构造验签名串
|
|
|
+ Formatter::joinedByLineFeed($inWechatpayTimestamp, $inWechatpayNonce, $inBody),
|
|
|
+ $inWechatpaySignature,
|
|
|
+ $platformPublicKeyInstance
|
|
|
+ );
|
|
|
+ }catch (\Exception $e){
|
|
|
+ Log::log('notify_refund_wechat_pay', '错误getMessage:' . $e->getMessage());
|
|
|
+ }
|
|
|
+ Log::log('notify_refund_wechat_pay', '验签:' . $verifiedStatus.'验签inWechatpayTimestamp:' . $inWechatpayTimestamp.'验签verifiedStatus:' . $inWechatpayNonce.'验签timeOffsetStatus:' . $timeOffsetStatus);
|
|
|
+ if ($timeOffsetStatus && $verifiedStatus) {
|
|
|
+ // 转换通知的JSON文本消息为PHP Array数组
|
|
|
+ $inBodyArray = (array)json_decode($inBody, true);
|
|
|
+ // 使用PHP7的数据解构语法,从Array中解构并赋值变量
|
|
|
+ ['resource' => [
|
|
|
+ 'ciphertext' => $ciphertext,
|
|
|
+ 'nonce' => $nonce,
|
|
|
+ 'associated_data' => $aad
|
|
|
+ ]] = $inBodyArray;
|
|
|
+ // 加密文本消息解密
|
|
|
+ $inBodyResource = AesGcm::decrypt($ciphertext, $apiv3Key, $nonce, $aad);
|
|
|
+ // 把解密后的文本转换为PHP Array数组
|
|
|
+ $inBodyResourceArray = (array)json_decode($inBodyResource, true);
|
|
|
+ Log::log('notify_refund_wechat_pay', '打印解密后的结果:' . json_encode($inBodyResourceArray));
|
|
|
+ Log::log('notify_refund_wechat_pay', '参数:' . $inBodyResourceArray['refund_status'] . '订单号' . $inBodyResourceArray['out_trade_no'] . '微信支付号' . $inBodyResourceArray['transaction_id']);
|
|
|
+ if ($inBodyResourceArray['refund_status'] == "SUCCESS") {
|
|
|
+ Log::log('notify_refund_wechat_pay', '通知订单');
|
|
|
+ $orderInfo = Orders::query()->where('snowflake_id','=',$inBodyResourceArray['out_trade_no'])->first()->toArray();
|
|
|
+ $status = 6;
|
|
|
+ //更新订单支付状态
|
|
|
+ $orderData = [
|
|
|
+ 'status'=>$status,
|
|
|
+ ];
|
|
|
+ // 组合数据,写入订单表,子表
|
|
|
+ DB::beginTransaction();
|
|
|
+ try {
|
|
|
+ $res = Orders::query()->where('snowflake_id','=',$inBodyResourceArray['out_trade_no'])->update($orderData);
|
|
|
+ Log::log('notify_refund_wechat_pay', '更新订单,snowflake_id:'.$inBodyResourceArray['out_trade_no'].';'. json_encode($res));
|
|
|
+ if (!$res) {
|
|
|
+ // 回退数据
|
|
|
+ DB::rollBack();
|
|
|
+ Log::log('notify_refund_wechat_pay', '更新订单失败' . json_encode($res));
|
|
|
+ return json_send(['code'=>'FAIL']);
|
|
|
+ }
|
|
|
+ //更新子订单
|
|
|
+ $res = OrdersProduct::query()->where('order_id','=',$orderInfo['id'])->update(['status'=>$status]);
|
|
|
+ Log::log('notify_refund_wechat_pay', '更新子订单,order_id:'.$orderInfo['id'].';'. json_encode($res));
|
|
|
+ if (!$res) {
|
|
|
+ Log::log('notify_refund_wechat_pay', '更新子订单失败:'.$orderInfo['id'].':'.$status . json_encode($res));
|
|
|
+ // 回退数据
|
|
|
+ DB::rollBack();
|
|
|
+ return json_send(['code'=>'FAIL']);
|
|
|
+ }
|
|
|
+ // 提交数据
|
|
|
+ DB::commit();
|
|
|
+ }catch (\Exception $e){
|
|
|
+ Log::log('notify_refund_wechat_pay', '更新订单失败' . json_encode($e));
|
|
|
+ return json_send(['code'=>'FAIL']);
|
|
|
+ }
|
|
|
+ $orderInfo = Orders::query()->where('snowflake_id','=',$inBodyResourceArray['out_trade_no'])->first()->toArray();
|
|
|
+ Log::log('notify_refund_wechat_pay', '支付回调完成 通知返回' . json_encode($orderInfo));
|
|
|
+ return json_send(['code'=>'SUCCESS']);
|
|
|
+
|
|
|
+ }
|
|
|
+ return json_send(['code'=>'SUCCESS']);
|
|
|
+ }else{
|
|
|
+ return json_send(['code'=>'FAIL']);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|