checkLogin(); $code = request('code',''); $amount = request('amount',''); if ($amount < 0.1) return json_send(['code'=>'error','msg'=>'提现失败,低于最低提现额度','data'=>['error'=>'提现失败,低于最低提现额度']]); if ($amount > 200) return json_send(['code'=>'error','msg'=>'提现失败,超出最高提现额度','data'=>['error'=>'提现失败,超出最高提现额度']]); $address = $CustomAddr->query()->where([['custom_uid','=',$uid],['contact_shop','<>','']])->first(); if (!$address) return json_send(['code'=>'error','msg'=>'请先填写收货地址和药店信息','data'=>['error'=>'请先填写收货地址和药店信息']]); // 获取余额信息 $amountInfo = $CustomAmount::query()->where(['custom_uid'=>$uid])->first(); if(!$amountInfo){ $result = $CustomAmountRecord::query()->insert(['custom_uid'=>$uid,'insert_time'=>time(),'update_time'=>time()]); if (!$result){ Log::error('wechat/transfer','获取余额信息失败'.'返回'.json_encode($result)); return json_send(['code'=>'error','msg'=>'提现失败','data'=>['error'=>'提现失败']]); } $balance = 0; }else{ $balance = $amountInfo['amount']; } // 如果剩余余额不足 if( $balance < $amount ) return json_send(['code'=>'error','msg'=>'余额不足','data'=>['error'=>'余额不足']]); //获取openid $resultOpenid = Mini::jscode2session($code); if (!$resultOpenid['openid']) return json_send(['code'=>'error','msg'=>'获取openid失败','data'=>$resultOpenid['error']]); $Snowflake = new Snowflake(); $SnowflakeId = $Snowflake->next(); $params['amount'] = $amount; $params['out_bill_no'] = $SnowflakeId; $params['openid'] = $resultOpenid['openid']; DB::beginTransaction(); try { //扣除用户余额 $amountUpdate = [ 'amount'=>DB::raw('amount+-'.$amount), 'use_amount'=>DB::raw('use_amount+'.$amount), 'update_time'=>time() ]; $result = $CustomAmount::query()->where(['custom_uid'=>$uid])->update($amountUpdate); if (!$result) { Log::error('wechat/transfer','提现申请失败'.'返回'.json_encode($amountUpdate).'结果'.json_encode($result)); return json_send(['code'=>'error','msg'=>'提现申请失败','data'=>['error'=>'扣除用户余额失败']]); } $Transfer = new Transfer(); $transferResult = $Transfer->pay($params); Log::error('wechat/transfer','微信商户转账'.'返回'.json_encode($transferResult)); if (!$transferResult || $transferResult['state'] !== 'WAIT_USER_CONFIRM') return json_send(['code'=>'error','msg'=>'提现申请失败','data'=>'提现申请失败']); //重新获取用户余额 $balance = $CustomAmount::query()->where(['custom_uid'=>$uid])->value('amount'); $data = [ 'custom_uid' => $uid, 'out_bill_no' => $transferResult['out_bill_no'], 'transfer_bill_no' => $transferResult['transfer_bill_no'], 'prefix' => 2, 'amount' => $amount, 'buy_type' => 2, 'pay_type' => 1, 'balance' => $balance, 'description' => '余额提现', 'status' => 1, ]; //写入余额记录 $recordResult = $CustomAmountRecord->add($data); if (!$recordResult) { DB::rollBack(); return json_send(['code'=>'error','msg'=>'提现申请失败','data'=>'写入余额记录失败']); } // 提交数据 DB::commit(); }catch (\Exception $e){ DB::rollBack(); return json_send(['code'=>'error','msg'=>'提现申请失败','data'=>'提现申请失败']); } $list = [ 'package_info' => $transferResult['package_info'], 'out_bill_no' => $transferResult['out_bill_no'], ]; return json_send(['code'=>'success','msg'=>'成功','data'=>$list]); } /** * 小程序微信商户转账回调 /api/wechat_pay/notify * * */ public function notify() { Log::error('wechat/transfer_notify', '提现转账回调开始'); $content = file_get_contents("php://input"); if (!empty($content)) { //直接json字符串 $params = $content; } elseif (!empty($_POST)) { //直接POST数据 $params = $_POST; } else { $params = []; } $post_data = $params; Log::error('wechat/transfer_notify', 'post_data:' . $post_data); //获取headers参数 $headers = request()->header(); Log::error('wechat/transfer_notify', '微信支付回调返回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::error('wechat/transfer_notify', '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::error('notify_wechat_transfer', '时间偏移量:' . $timeOffsetStatus); $verifiedStatus = Rsa::verify( // 构造验签名串 Formatter::joinedByLineFeed($inWechatpayTimestamp, $inWechatpayNonce, $inBody), $inWechatpaySignature, $platformPublicKeyInstance ); Log::error('wechat/transfer_notify', '验签:' . $verifiedStatus.'验签inWechatpayTimestamp:' . $inWechatpayTimestamp.'验签verifiedStatus:' . $inWechatpayNonce); 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::error('wechat/transfer_notify', '打印解密后的结果:' . json_encode($inBodyResourceArray)); Log::error('wechat/transfer_notify', '参数:' . $inBodyResourceArray['state'] . '订单号' . $inBodyResourceArray['out_bill_no'] . '微信支付号' . $inBodyResourceArray['transfer_bill_no']); $amountInfo = CustomAmountRecord::query()->where('out_bill_no','=',$inBodyResourceArray['out_bill_no'])->first(); if (!$amountInfo) { Log::error('wechat/transfer_notify', '获取余额记录信息失败' . json_encode($amountInfo)); return json_send(['code'=>'FAIL']); } if ($inBodyResourceArray['state'] == "SUCCESS") { $transfer_amount = $inBodyResourceArray['transfer_amount']/100; //更新余额记录状态 $data = [ 'pay_time' => time(), 'status'=>2, ]; $res = CustomAmountRecord::query()->where('out_bill_no','=',$inBodyResourceArray['out_bill_no'])->update($data); Log::error('wechat/transfer_notify', '更新余额记录,snowflake_id:'.$inBodyResourceArray['out_bill_no'].';'. json_encode($res)); if (!$res) { Log::error('wechat/transfer_notify', '更新余额记录失败' . json_encode($res)); return json_send(['code'=>'FAIL']); } //更新用户提现成功数额 $res = CustomAmount::query()->where('custom_uid','=',$amountInfo['custom_uid'])->update(['transfer_amount'=>DB::raw('transfer_amount+'.$transfer_amount)]); Log::error('wechat/transfer_notify', '更新用户提现成功数额,custom_uid:'.$amountInfo['custom_uid'].';'. json_encode($res)); if (!$res) { Log::error('wechat/transfer_notify', '更新余额记录失败' . json_encode($res)); return json_send(['code'=>'FAIL']); } Log::error('wechat/transfer_notify', '支付回调完成 通知返回' . json_encode($data)); }elseif ($inBodyResourceArray['state'] == "FAIL"){ //更新余额订单状态 $data = [ 'status'=>3 ]; $res = CustomAmountRecord::query()->where('out_bill_no','=',$inBodyResourceArray['out_bill_no'])->update($data); Log::error('wechat/transfer_notify', '更新余额记录,out_bill_no:'.$inBodyResourceArray['out_bill_no'].';'. json_encode($res)); if (!$res) { Log::error('wechat/transfer_notify', '更新余额记录失败' . json_encode($res)); return json_send(['code'=>'FAIL']); } //退回余额 $amountUpdate = [ 'amount'=>DB::raw('amount+'.$amountInfo['amount']), 'use_amount'=>DB::raw('use_amount-'.$amountInfo['amount']), 'update_time'=>time() ]; $result = CustomAmount::query()->where(['custom_uid'=>$amountInfo['custom_uid']])->update($amountUpdate); if (!$result) { return json_send(['code'=>'error','msg'=>'提现失败退回余额失败','data'=>['error'=>'退回用户余额失败']]); } Log::error('wechat/transfer_notify', '回调完成 通知返回' . json_encode($amountInfo)); } return json_send(['code'=>'SUCCESS']); }else{ return json_send(['code'=>'FAIL']); } }catch (\Exception $e){ Log::error('wechat/transfer_notify', '回调失败getMessage:' . $e->getMessage()); } return json_send(['code'=>'SUCCESS']); } }