272 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			PHP
		
	
	
		
		
			
		
	
	
			272 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			PHP
		
	
	
| 
								 | 
							
								<?php
							 | 
						|||
| 
								 | 
							
								namespace app\admin\logic;
							 | 
						|||
| 
								 | 
							
								/**
							 | 
						|||
| 
								 | 
							
								 * 功能: 微信企业付款
							 | 
						|||
| 
								 | 
							
								 * 用途:企业向微信用户个人付款
							 | 
						|||
| 
								 | 
							
								 * 证书:需要
							 | 
						|||
| 
								 | 
							
								 * 失败后一定要用【原来的商户订单号】去重试,不然有可能存在重复支付的风险!!!
							 | 
						|||
| 
								 | 
							
								 * 商户订单号: 必须唯一且需要为33位以下的数字或字母
							 | 
						|||
| 
								 | 
							
								 */
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								use EasyWeChat\Factory;
							 | 
						|||
| 
								 | 
							
								use app\common\model\Pay;
							 | 
						|||
| 
								 | 
							
								use app\common\server\ConfigServer;
							 | 
						|||
| 
								 | 
							
								use app\common\server\WeChatServer;
							 | 
						|||
| 
								 | 
							
								use think\facade\Db;
							 | 
						|||
| 
								 | 
							
								use app\common\logic\AccountLogLogic;
							 | 
						|||
| 
								 | 
							
								use app\common\model\AccountLog;
							 | 
						|||
| 
								 | 
							
								use app\common\model\user\User;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								class WechatCorporatePaymentLogic
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								  /**
							 | 
						|||
| 
								 | 
							
								   * 获取app
							 | 
						|||
| 
								 | 
							
								   */
							 | 
						|||
| 
								 | 
							
								  public static function getApp($client)
							 | 
						|||
| 
								 | 
							
								  {
							 | 
						|||
| 
								 | 
							
								    $config = WeChatServer::getPayConfigBySource($client)['config'];
							 | 
						|||
| 
								 | 
							
								    $app = Factory::payment($config);
							 | 
						|||
| 
								 | 
							
								    return $app;
							 | 
						|||
| 
								 | 
							
								  }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								  /**
							 | 
						|||
| 
								 | 
							
								   * 企业付款
							 | 
						|||
| 
								 | 
							
								   */
							 | 
						|||
| 
								 | 
							
								  public static function pay($withdraw)
							 | 
						|||
| 
								 | 
							
								  {
							 | 
						|||
| 
								 | 
							
								    // 微信零钱最小提现金额 1元
							 | 
						|||
| 
								 | 
							
								    if($withdraw['left_money'] < 1) {
							 | 
						|||
| 
								 | 
							
								      return [
							 | 
						|||
| 
								 | 
							
								        'code' => 0,
							 | 
						|||
| 
								 | 
							
								        'msg' => '扣除手续费后提现金额不能小于1元'
							 | 
						|||
| 
								 | 
							
								      ];
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								    // 每天最多可向同一用户付款10次
							 | 
						|||
| 
								 | 
							
								    $count = Db::name('withdraw_apply')
							 | 
						|||
| 
								 | 
							
								      ->whereTime('update_time', 'd') // 今天
							 | 
						|||
| 
								 | 
							
								      ->where('user_id', $withdraw['user_id'])
							 | 
						|||
| 
								 | 
							
								      ->where('type', 2) // 微信零钱
							 | 
						|||
| 
								 | 
							
								      ->where('status', '>=', 2) // 提现中、提现成功、提现失败
							 | 
						|||
| 
								 | 
							
								      ->count();
							 | 
						|||
| 
								 | 
							
								    if($count > 10) {
							 | 
						|||
| 
								 | 
							
								      return [
							 | 
						|||
| 
								 | 
							
								        'code' => 0,
							 | 
						|||
| 
								 | 
							
								        'msg' => '同一个用户一天最多可付款10次'
							 | 
						|||
| 
								 | 
							
								      ];
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								    // 一天一个用户累计提现金额不能超过5000元
							 | 
						|||
| 
								 | 
							
								    $sum = Db::name('withdraw_apply')
							 | 
						|||
| 
								 | 
							
								      ->whereTime('update_time', 'd') // 今天
							 | 
						|||
| 
								 | 
							
								      ->where('user_id', $withdraw['user_id'])
							 | 
						|||
| 
								 | 
							
								      ->where('type', 2) // 微信零钱
							 | 
						|||
| 
								 | 
							
								      ->where('status', 'in', [2, 3]) // 提现中、提现成功
							 | 
						|||
| 
								 | 
							
								      ->sum('left_money');
							 | 
						|||
| 
								 | 
							
								    $sum = $sum + $withdraw['left_money'];
							 | 
						|||
| 
								 | 
							
								    if($sum > 5000) {
							 | 
						|||
| 
								 | 
							
								      return [
							 | 
						|||
| 
								 | 
							
								        'code' => 0,
							 | 
						|||
| 
								 | 
							
								        'msg' => '一天一个用户累计提现金额(不算手续费)不能超过5000元'
							 | 
						|||
| 
								 | 
							
								      ];
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 用户授权信息(同一个用户可能有多条,取client最小的一条)
							 | 
						|||
| 
								 | 
							
								    $userAuth = Db::name('user_auth')->where('user_id', $withdraw['user_id'])->order('client', 'asc')->find();
							 | 
						|||
| 
								 | 
							
								    if(!$userAuth) {
							 | 
						|||
| 
								 | 
							
								      // 无授权记录
							 | 
						|||
| 
								 | 
							
								      return [
							 | 
						|||
| 
								 | 
							
								        'code'=> 0,
							 | 
						|||
| 
								 | 
							
								        'msg' => '查询不到该用户的openid'
							 | 
						|||
| 
								 | 
							
								      ];
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								    // 获取app
							 | 
						|||
| 
								 | 
							
								    $app = self::getApp($userAuth['client']);
							 | 
						|||
| 
								 | 
							
								    // 商户唯一订单号
							 | 
						|||
| 
								 | 
							
								    $partner_trade_no = $withdraw['sn'];
							 | 
						|||
| 
								 | 
							
								    // 发起企业付款
							 | 
						|||
| 
								 | 
							
								    $result = $app->transfer->toBalance([
							 | 
						|||
| 
								 | 
							
								      // 商户订单号,需保持唯一性(只能是字母或者数字,不能包含有符号)
							 | 
						|||
| 
								 | 
							
								      'partner_trade_no' => $partner_trade_no, 
							 | 
						|||
| 
								 | 
							
								      'openid' => $userAuth['openid'],
							 | 
						|||
| 
								 | 
							
								      // NO_CHECK:不校验真实姓名, FORCE_CHECK:强校验真实姓名
							 | 
						|||
| 
								 | 
							
								      'check_name' => 'NO_CHECK', 
							 | 
						|||
| 
								 | 
							
								      // 如果 check_name 设置为FORCE_CHECK,则必填用户真实姓名
							 | 
						|||
| 
								 | 
							
								      're_user_name' => '', 
							 | 
						|||
| 
								 | 
							
								      // 企业付款金额,单位为分 100分=1元
							 | 
						|||
| 
								 | 
							
								      'amount' => 100 * $withdraw['left_money'],
							 | 
						|||
| 
								 | 
							
								      // 企业付款操作说明信息。必填
							 | 
						|||
| 
								 | 
							
								      'desc' => '佣金提现'
							 | 
						|||
| 
								 | 
							
								    ]);
							 | 
						|||
| 
								 | 
							
								    // 马上将提现申请单状态修改为提现中,并记录微信返回信息,避免同一提现单多次点击发起多次企业付款
							 | 
						|||
| 
								 | 
							
								    $fiterField = ['appid','mch_appid', 'mchid', 'mch_id', 'openid']; // 过滤敏感字段
							 | 
						|||
| 
								 | 
							
								    $filterResult = array_filter($result, function($key) use ($fiterField) {
							 | 
						|||
| 
								 | 
							
								      return !in_array($key, $fiterField);
							 | 
						|||
| 
								 | 
							
								    }, ARRAY_FILTER_USE_KEY);
							 | 
						|||
| 
								 | 
							
								    Db::name('withdraw_apply')
							 | 
						|||
| 
								 | 
							
								      ->where('id', $withdraw['id'])
							 | 
						|||
| 
								 | 
							
								      ->update([
							 | 
						|||
| 
								 | 
							
								        'status' => 2, // 提现中
							 | 
						|||
| 
								 | 
							
								        'update_time' => time(),
							 | 
						|||
| 
								 | 
							
								        'pay_desc' => json_encode($filterResult)
							 | 
						|||
| 
								 | 
							
								      ]);
							 | 
						|||
| 
								 | 
							
								    // 通信标识 return_code
							 | 
						|||
| 
								 | 
							
								    if($result['return_code'] == 'SUCCESS') {
							 | 
						|||
| 
								 | 
							
								      // 业务结果 result_code
							 | 
						|||
| 
								 | 
							
								      if($result['result_code'] == 'SUCCESS') {
							 | 
						|||
| 
								 | 
							
								        // 企业付款成功, 更新提现申请单状态为提现成功并记录支付单号及支付时间
							 | 
						|||
| 
								 | 
							
								        Db::name('withdraw_apply')
							 | 
						|||
| 
								 | 
							
								          ->where('id', $withdraw['id'])
							 | 
						|||
| 
								 | 
							
								          ->update([
							 | 
						|||
| 
								 | 
							
								            'status' => 3, // 提现成功
							 | 
						|||
| 
								 | 
							
								            'payment_no' => $result['payment_no'],
							 | 
						|||
| 
								 | 
							
								            'payment_time' => strtotime($result['payment_time']),
							 | 
						|||
| 
								 | 
							
								            'update_time' => time()
							 | 
						|||
| 
								 | 
							
								          ]);
							 | 
						|||
| 
								 | 
							
								        return [
							 | 
						|||
| 
								 | 
							
								          'code' => 1,
							 | 
						|||
| 
								 | 
							
								          'msg' => '成功提现至微信零钱'
							 | 
						|||
| 
								 | 
							
								        ];
							 | 
						|||
| 
								 | 
							
								      }else{
							 | 
						|||
| 
								 | 
							
								        return [
							 | 
						|||
| 
								 | 
							
								          'code' => 0,
							 | 
						|||
| 
								 | 
							
								          'msg' => $result['err_code_des']
							 | 
						|||
| 
								 | 
							
								        ];
							 | 
						|||
| 
								 | 
							
								      }
							 | 
						|||
| 
								 | 
							
								    }else{
							 | 
						|||
| 
								 | 
							
								      // 提现至零钱失败,更新提现申请单为提现失败,并回退佣金
							 | 
						|||
| 
								 | 
							
								      Db::name('withdraw_apply')
							 | 
						|||
| 
								 | 
							
								          ->where('id', $withdraw['id'])
							 | 
						|||
| 
								 | 
							
								          ->update([
							 | 
						|||
| 
								 | 
							
								            'status' => 4, // 提现失败
							 | 
						|||
| 
								 | 
							
								            'update_time' => time()
							 | 
						|||
| 
								 | 
							
								          ]);
							 | 
						|||
| 
								 | 
							
								      //回退佣金
							 | 
						|||
| 
								 | 
							
								      $user = User::find($withdraw['user_id']);
							 | 
						|||
| 
								 | 
							
								      $user->earnings = ['inc', $withdraw['money']];
							 | 
						|||
| 
								 | 
							
								      $user->save();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								      //增加佣金变动记录
							 | 
						|||
| 
								 | 
							
								      AccountLogLogic::AccountRecord(
							 | 
						|||
| 
								 | 
							
								          $withdraw['user_id'],
							 | 
						|||
| 
								 | 
							
								          $withdraw['money'],
							 | 
						|||
| 
								 | 
							
								          1,
							 | 
						|||
| 
								 | 
							
								          AccountLog::withdraw_back_earnings,
							 | 
						|||
| 
								 | 
							
								          '',
							 | 
						|||
| 
								 | 
							
								          $withdraw['id'],
							 | 
						|||
| 
								 | 
							
								          $withdraw['sn']
							 | 
						|||
| 
								 | 
							
								      );
							 | 
						|||
| 
								 | 
							
								      return [
							 | 
						|||
| 
								 | 
							
								        'code' => 0,
							 | 
						|||
| 
								 | 
							
								        'msg' => $result['return_msg']
							 | 
						|||
| 
								 | 
							
								      ];
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								  }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								  /**
							 | 
						|||
| 
								 | 
							
								   * 查询企业付款
							 | 
						|||
| 
								 | 
							
								   */
							 | 
						|||
| 
								 | 
							
								  public static function search($withdraw)
							 | 
						|||
| 
								 | 
							
								  {
							 | 
						|||
| 
								 | 
							
								    $userAuth = Db::name('user_auth')->where('user_id', $withdraw['user_id'])->order('client', 'asc')->find();
							 | 
						|||
| 
								 | 
							
								    if(!$userAuth) {
							 | 
						|||
| 
								 | 
							
								      // 无授权记录
							 | 
						|||
| 
								 | 
							
								      return [
							 | 
						|||
| 
								 | 
							
								        'code'=> 0,
							 | 
						|||
| 
								 | 
							
								        'msg' => '查询不到该用户的openid'
							 | 
						|||
| 
								 | 
							
								      ];
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								    $app = self::getApp($userAuth['client']);
							 | 
						|||
| 
								 | 
							
								    $partnerTradeNo = $withdraw['sn'];
							 | 
						|||
| 
								 | 
							
								    $result = $app->transfer->queryBalanceOrder($partnerTradeNo);
							 | 
						|||
| 
								 | 
							
								    $fiterField = ['appid','mch_appid', 'mchid', 'mch_id', 'openid']; // 过滤敏感字段
							 | 
						|||
| 
								 | 
							
								    $filterResult = array_filter($result, function($key) use ($fiterField) {
							 | 
						|||
| 
								 | 
							
								      return !in_array($key, $fiterField);
							 | 
						|||
| 
								 | 
							
								    }, ARRAY_FILTER_USE_KEY );
							 | 
						|||
| 
								 | 
							
								    // 记录查询结果
							 | 
						|||
| 
								 | 
							
								    Db::name('withdraw_apply')
							 | 
						|||
| 
								 | 
							
								      ->where('id', $withdraw['id'])
							 | 
						|||
| 
								 | 
							
								      ->update([
							 | 
						|||
| 
								 | 
							
								        'update_time' => time(),
							 | 
						|||
| 
								 | 
							
								        'pay_search_desc' => json_encode($filterResult)
							 | 
						|||
| 
								 | 
							
								      ]);
							 | 
						|||
| 
								 | 
							
								    if($result['return_code'] == 'SUCCESS') { // 通信标识
							 | 
						|||
| 
								 | 
							
								      if($result['result_code'] == 'SUCCESS') { // 另一个标识
							 | 
						|||
| 
								 | 
							
								        if($result['status'] == 'SUCCESS') { // 业务结果
							 | 
						|||
| 
								 | 
							
								          // 转账成功,标记提现申请单为提现成功,记录支付信息
							 | 
						|||
| 
								 | 
							
								          Db::name('withdraw_apply')
							 | 
						|||
| 
								 | 
							
								          ->where('id', $withdraw['id'])
							 | 
						|||
| 
								 | 
							
								          ->update([
							 | 
						|||
| 
								 | 
							
								            'status' => 3, // 提现成功
							 | 
						|||
| 
								 | 
							
								            'payment_no' => $result['detail_id'],
							 | 
						|||
| 
								 | 
							
								            'payment_time' => strtotime($result['payment_time']),
							 | 
						|||
| 
								 | 
							
								            'update_time' => time()
							 | 
						|||
| 
								 | 
							
								          ]);
							 | 
						|||
| 
								 | 
							
								          return [
							 | 
						|||
| 
								 | 
							
								            'code' => 1,
							 | 
						|||
| 
								 | 
							
								            'msg' => '已提现成功'
							 | 
						|||
| 
								 | 
							
								          ];
							 | 
						|||
| 
								 | 
							
								        }else if($result['status'] == 'FAILED'){
							 | 
						|||
| 
								 | 
							
								          // 转账失败
							 | 
						|||
| 
								 | 
							
								          Db::name('withdraw_apply')
							 | 
						|||
| 
								 | 
							
								          ->where('id', $withdraw['id'])
							 | 
						|||
| 
								 | 
							
								          ->update([
							 | 
						|||
| 
								 | 
							
								            'status' => 4, // 提现失败
							 | 
						|||
| 
								 | 
							
								            'update_time' => time()
							 | 
						|||
| 
								 | 
							
								          ]);
							 | 
						|||
| 
								 | 
							
								          //回退佣金
							 | 
						|||
| 
								 | 
							
								          $user = User::find($withdraw['user_id']);
							 | 
						|||
| 
								 | 
							
								          $user->earnings = ['inc', $withdraw['money']];
							 | 
						|||
| 
								 | 
							
								          $user->save();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								          //增加佣金变动记录
							 | 
						|||
| 
								 | 
							
								          AccountLogLogic::AccountRecord(
							 | 
						|||
| 
								 | 
							
								              $withdraw['user_id'],
							 | 
						|||
| 
								 | 
							
								              $withdraw['money'],
							 | 
						|||
| 
								 | 
							
								              1,
							 | 
						|||
| 
								 | 
							
								              AccountLog::withdraw_back_earnings,
							 | 
						|||
| 
								 | 
							
								              '',
							 | 
						|||
| 
								 | 
							
								              $withdraw['id'],
							 | 
						|||
| 
								 | 
							
								              $withdraw['sn']
							 | 
						|||
| 
								 | 
							
								          );
							 | 
						|||
| 
								 | 
							
								          return [
							 | 
						|||
| 
								 | 
							
								            'code' => 0,
							 | 
						|||
| 
								 | 
							
								            'msg' => '提现至微信零钱失败'
							 | 
						|||
| 
								 | 
							
								          ];
							 | 
						|||
| 
								 | 
							
								        }else{
							 | 
						|||
| 
								 | 
							
								          return [
							 | 
						|||
| 
								 | 
							
								            'code' => 0,
							 | 
						|||
| 
								 | 
							
								            'msg' => $result['reason']
							 | 
						|||
| 
								 | 
							
								          ];
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								      }else{
							 | 
						|||
| 
								 | 
							
								        // 查看这个提现单今天是否有重新发起过付款,如果没有则尝试使用【相同的商户订单号】再次发起付款
							 | 
						|||
| 
								 | 
							
								        // $count = Db::name('withdraw_apply')
							 | 
						|||
| 
								 | 
							
								        // ->whereTime('repay_time', 'd') // 今天
							 | 
						|||
| 
								 | 
							
								        // ->where('id', $withdraw['id']) // 提现申请单号
							 | 
						|||
| 
								 | 
							
								        // ->count();
							 | 
						|||
| 
								 | 
							
								        // if(!$count) {
							 | 
						|||
| 
								 | 
							
								        //   // 记录重新发起支付的时间
							 | 
						|||
| 
								 | 
							
								        //   Db::name('withdraw_apply')->where('id', $withdraw['id'])->update([
							 | 
						|||
| 
								 | 
							
								        //     'repay_time' => time(),
							 | 
						|||
| 
								 | 
							
								        //     'update_time' => time()
							 | 
						|||
| 
								 | 
							
								        //   ]);
							 | 
						|||
| 
								 | 
							
								        //   return self::pay($withdraw);
							 | 
						|||
| 
								 | 
							
								        // }else{
							 | 
						|||
| 
								 | 
							
								        //   return [
							 | 
						|||
| 
								 | 
							
								        //     'code' => 0,
							 | 
						|||
| 
								 | 
							
								        //     'msg' => $result['err_code_des']
							 | 
						|||
| 
								 | 
							
								        //   ];
							 | 
						|||
| 
								 | 
							
								        // }
							 | 
						|||
| 
								 | 
							
								        return [
							 | 
						|||
| 
								 | 
							
								          'code' => 0,
							 | 
						|||
| 
								 | 
							
								          'msg' => $result['err_code_des']
							 | 
						|||
| 
								 | 
							
								        ];
							 | 
						|||
| 
								 | 
							
								      }
							 | 
						|||
| 
								 | 
							
								    }else{
							 | 
						|||
| 
								 | 
							
								      return [
							 | 
						|||
| 
								 | 
							
								        'code' => 0,
							 | 
						|||
| 
								 | 
							
								        'msg' => $result['return_msg']
							 | 
						|||
| 
								 | 
							
								      ];
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								  }
							 | 
						|||
| 
								 | 
							
								}
							 |