123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- <?php namespace App\Http\Controllers\Api;
- use App\Http\Controllers\Api\Api;
- use App\Models\Custom;
- use App\Facades\Servers\Logs\Log;
- use App\Models\CustomAmount;
- use App\Models\CustomAmountRecord;
- use Illuminate\Http\Request;
- use App\Servers\WechatPay\Transfer;
- use Kra8\Snowflake\Snowflake;
- 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 WechatTransfer extends Api{
- /**
- * 小程序微信提现 商户转账 /api/wechat_pay/transfer
- *
- * */
- public function transfer(Custom $Custom,CustomAmount $CustomAmount,CustomAmountRecord $CustomAmountRecord)
- {
- // 检查登录
- $uid = $this->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'=>'提现失败,超出最高提现额度']]);
- // 获取余额信息
- $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){
- 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) {
- 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'=>'提现申请失败']);
- $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']);
- }
- }
|