// +---------------------------------------------------------------------- namespace App\Services\Common; use App\Models\CapitalLogModel; use App\Models\CoinLogModel; use App\Models\MemberModel; use App\Models\UserModel; use App\Services\BaseService; use App\Services\ConfigService; use App\Services\RedisService; use App\Services\UsdtWalletService; use Earnp\GoogleAuthenticator\GoogleAuthenticator; /** * 币种明细(提币、存币)-服务类 * Class CoinLogService * @package App\Services\Common */ class CoinLogService extends BaseService { // 静态对象 protected static $instance = null; /** * 构造函数 * @since 2020/11/10 * CoinLogService constructor. */ public function __construct() { $this->model = new CoinLogModel(); $this->memberModel = new MemberModel(); $this->capitalModel = new CapitalLogModel(); } /** * 静态入口 * @return static|null */ public static function make() { if (!self::$instance) { self::$instance = (new static()); } return self::$instance; } /** * 获取列表 * @param $params 参数 * @param int $pageSize 分页大小:默认 15 * @return array */ public function getDataList($params, $pageSize = 15) { $where = ['a.mark' => 1]; $type = isset($params['type'])? $params['type'] : 1; $status = isset($params['status'])? $params['status'] : 0; $changeType = isset($params['change_type'])? $params['change_type'] : 1; $contactType = isset($params['contact_type'])? $params['contact_type'] : 1; $coinType = isset($params['coin_type'])? $params['coin_type'] : 1; $userId = isset($params['user_id'])? $params['user_id'] : 0; if($type>0){ $where['a.type'] = $type; } if($status>0){ $where['a.status'] = $status; } if($contactType>0){ $where['a.contact_type'] = $contactType; } if($changeType>0){ $where['a.change_type'] = $changeType; } if($coinType>0){ $where['a.coin_type'] = $coinType; } if($userId>0){ $where['a.user_id'] = $userId; } $list = $this->model->from('coin_logs as a') ->leftJoin('member as m', 'm.id', '=', 'a.user_id') ->where($where) ->where(function ($query) use($params){ $keyword = isset($params['keyword'])? $params['keyword'] : ''; if($keyword){ $query->where('a.order_no','like',"{$keyword}")->orWhere('m.username','like',"%{$keyword}%"); } // 日期 $date = isset($params['date']) ? $params['date'] : []; $start = isset($date[0])? $date[0] : ''; $end = isset($date[1])? $date[1] : ''; $end = $start>=$end? '' : $end; if ($start) { $query->where('a.create_time','>=', strtotime($start)); } if($end){ $query->where('a.create_time','<', strtotime($end)); } }) ->select(['a.*', 'm.username']) ->orderBy('a.create_time','desc') ->paginate($pageSize > 0 ? $pageSize : 9999999); $list = $list? $list->toArray() :[]; if($list){ foreach($list['data'] as &$item){ $item['from_address_text'] = $item['from_address']? format_address($item['from_address']):''; $item['to_address_text'] = $item['to_address']? format_address($item['to_address']):''; $item['create_time_text'] = $item['create_time']? datetime(strtotime($item['create_time']), 'Y-m-d H:i'):''; $item['time_text'] = $item['create_time']? datetime(strtotime($item['create_time']), 'm-d H:i'):''; } } return [ 'pageSize'=> $pageSize, 'total'=>isset($list['total'])? $list['total'] : 0, 'list'=> isset($list['data'])? $list['data'] : [] ]; } /** * 验证是否存在 * @param \App\Services\字段名 $field * @param \App\Services\字段值 $value * @param string $pk * @return mixed */ public function checkExists($field, $value, $pk = 'id', $status=0) { $cacheKey = "caches:coinLogs:exists:{$field}_{$value}"; if($result = RedisService::get($cacheKey)){ return $result; } $result = parent::checkExists($field, $value, $pk, $status); if($result){ RedisService::set($cacheKey, $result, rand(3,5)); } return $result; } /** * 根据交易订单号获取提币记录 * @param $txid * @return array|false|mixed */ public function getCacheInfoByTxid($txid) { $cacheKey = "caches:wallets:coinLog:{$txid}"; if($data = RedisService::get($cacheKey)){ return $data; } $data = $this->model->where(['txid' => $txid]) ->select(['id', 'user_id','order_no', 'num','free', 'coin_type', 'balance', 'change_type', 'status']) ->first(); if($data){ RedisService::set($cacheKey, $data, rand(3,5)); } return $data; } /** * 提币/转账 * @param $userId 用户 * @param $params 参数:to_address-提币地址,num-数量,contact_type-合约类型 * @return bool */ public function withdraw($userId, $params) { $num = isset($params['num'])? floatval($params['num']) : 0; $toAddress = isset($params['to_address'])? $params['to_address'] : ''; $contactType = isset($params['contact_type'])? intval($params['contact_type']) : 1; if(empty($userId) || empty($toAddress)){ $this->error ='1013'; return false; } $userInfo = MemberService::make()->getInfo($userId); if(empty($userInfo) || $userInfo['status'] != 1){ $this->error = '2009'; return false; } if(!in_array($contactType, [1,2])){ $this->error ='2209'; return false; } // 交易密码 $tradePassword = isset($params['trade_password'])? $params['trade_password'] : ''; $password = isset($userInfo['trade_password'])? $userInfo['trade_password'] : ''; if (empty($password)) { $this->error = '2015'; return false; } if (!$tradePassword || get_password($tradePassword . md5($tradePassword . 'otc')) != $password) { $this->error = '2016'; return false; } $config = ConfigService::make()->getConfigOptionByGroup(6); $coinOutFree = isset($config['coin_out_free'])? floatval($config['coin_out_free']) : 0; $googleLimitTime = isset($config['google_limit_time'])? floatval($config['google_limit_time']) : 0; $fee = floatval($num * $coinOutFree/100); // TRC20 if($contactType == 1){ $coinOutMin = isset($config['trc_out_limit'])? floatval($config['trc_out_limit']) : 0; $coinOutMax = isset($config['trc_out_max'])? floatval($config['trc_out_max']) : 0; }else{ $coinOutMin = isset($config['erc_out_limit'])? floatval($config['erc_out_limit']) : 0; $coinOutMax = isset($config['erc_out_max'])? floatval($config['erc_out_max']) : 0; } // 谷歌验证码 $checkGoogle = isset($params['check_google'])? $params['check_google'] : 1; if($checkGoogle){ $googleCode = isset($params['google_code'])? $params['google_code'] : ''; $info = UserModel::where(['user_id'=> $userId])->select(['google_secret','google_verify_time'])->first(); $googleSecret = isset($info['google_secret'])? $info['google_secret'] : ''; $verifyTime = isset($info['google_verify_time'])? intval($info['google_verify_time']) : 0; if(empty($googleSecret)){ $this->error = '2017'; return false; } // 刚验证更新的谷歌验证码24小时内不得提币 if($verifyTime && $verifyTime> time()){ $this->error = lang('2019',['time'=>$googleLimitTime]); return false; } if (!GoogleAuthenticator::CheckCode($googleSecret, $googleCode)) { $this->error = '2018'; return false; } }else{ // 身份认证 if($userInfo['idcard_check'] != 1){ $this->error = '2018'; return false; } } // 单笔限额 if($num<$coinOutMin || $num > $coinOutMax){ $this->error = '5004'; return false; } // 余额是否足够 if($userInfo['usdt_num'] < floatval($num + $fee)){ $this->error = '2212'; return false; } $orderNo = get_order_num('Tw'); $data = [ 'type'=> isset($params['type'])? $params['type'] : 1, 'user_id'=> $userId, 'from_address'=> '', 'to_address'=> $toAddress, 'change_type'=> 2, 'coin_type'=> isset($params['coin_type'])? $params['coin_type'] : 1, 'contact_type'=> $contactType, 'order_no'=> $orderNo, 'txid'=> uniqid(), 'num'=> $num, 'free'=> $fee, 'balance'=> $userInfo['usdt_num'], 'create_time'=> time(), 'update_time'=> time(), 'status'=> 3, 'mark'=> 1, ]; $this->model->startTrans(); if(!$this->model->edit($data)){ $this->model->rollBack(); $this->error = '2013'; return false; } // 扣除余额 if(!$this->memberModel->where(['id'=> $userId,'mark'=>1])->decrement('usdt_num', ($num + $fee))){ $this->model->rollBack(); $this->error = '2014'; return false; } $data = [ 'order_no'=> $orderNo, 'user_id'=> $userId, 'type'=> 5, 'pay_type'=> 1, 'change_type'=> 2, 'num'=> ($num+$fee), 'total'=> 0, 'balance'=> floatval($userInfo['usdt_num']-($num+$fee)), 'create_time'=> time(), 'update_time'=> time(), 'status'=> 1, 'mark'=>1, 'remark'=> '提币', ]; if(!$this->capitalModel->edit($data)){ $this->model->rollBack(); $this->error = '3014'; return false; } $this->model->commit(); $this->error = '2216'; return true; } /** * 转账审核 * @param $adminId * @param $params * @return bool * @throws \Tron\Exceptions\TransactionException * @throws \Tron\Exceptions\TronErrorException */ public function confirmWithdraw($adminId, $params) { $id = isset($params['id'])? $params['id'] : 0; $checkStatus = isset($params['status'])? $params['status'] : 0; if(empty($id) || !in_array($checkStatus, [2,4])){ $this->error ='1013'; return false; } $info = $this->model->getInfo($id); $status = isset($info['status'])? $info['status'] : 0; $contactType = isset($info['contact_type'])? $info['contact_type'] : 0; $num = isset($info['num'])? $info['num'] : 0; $fee = isset($info['fee'])? $info['fee'] : 0; $userId = isset($info['user_id'])? $info['user_id'] : 0; $total = floatval($num+$fee); if(empty($info) || empty($userId)){ $this->error = '1026'; return false; } // 待审核状态 if($status != 3 && $checkStatus != 2){ $this->error = '5001'; return false; } if($checkStatus == 2 && !in_array($status, [3,4])){ $this->error = '5001'; return false; } $userInfo = MemberService::make()->getInfo($userId); // 审核失败 $this->model->startTrans(); if($checkStatus == 2){ if(!$this->model->where(['id'=> $id])->update(['status'=> 2,'update_time'=>time()])){ $this->model->rollBack(); $this->error = '5002'; return false; } // 退还 if($total>0){ if(!$this->memberModel->where(['id'=> $userId])->increment('usdt_num', $total)){ $this->model->rollBack(); $this->error = '5003'; return false; } $usdtNum = isset($userInfo['usdt_num'])? $userInfo['usdt_num'] : 0; $data = [ 'order_no'=> $info['order_no'], 'user_id'=> $userId, 'type'=> 6, 'pay_type'=> 1, 'change_type'=> 1, 'num'=> $total, 'total'=> 0, 'balance'=> floatval($usdtNum + $total), 'create_time'=> time(), 'update_time'=> time(), 'status'=> 1, 'mark'=>1, 'remark'=> '提币失败退还', ]; if(!$this->capitalModel->edit($data)){ $this->model->rollBack(); $this->error = '3014'; return false; } } } // 审核成功,播币 else if($checkStatus == 4){ $config = ConfigService::make()->getConfigOptionByGroup(5); $trcOutAddress = isset($config['trc_out_address'])? $config['trc_out_address'] : ''; $ercOutAddress = isset($config['erc_out_address'])? $config['erc_out_address'] : ''; // TRC if($contactType==1){ if($contactType==1 && empty($trcOutAddress)){ $this->error = '2017'; return false; } // 钱包余额 $balance = UsdtWalletService::make()->getTrc20Usdt($trcOutAddress); if($balance < $total){ $this->error = '2019'; return false; } // 转钱 if(!$result = UsdtWalletService::make()->usdtTrcTransfer($userInfo['trc_address'],$num)){ $this->model->rollBack(); $this->error = '5002'; return false; } if(!$this->model->where(['id'=> $id])->update(['txid'=> $result['txID'],'status'=> 4,'update_time'=>time()])){ $this->model->rollBack(); $this->error = '5002'; return false; } return true; } // ERC else if($contactType==2){ if(empty($ercOutAddress)){ $this->error = '2018'; return false; } // 钱包余额 $balance = UsdtWalletService::make()->getErc20Usdt($ercOutAddress); if($balance < $total){ $this->error = '2019'; return false; } if(!$this->model->where(['id'=> $id])->update(['status'=> 4,'update_time'=>time()])){ $this->model->rollBack(); $this->error = '5002'; return false; } } // 退还 if($total>0){ $userInfo = MemberService::make()->getInfo($userId); if(!$this->memberModel->where(['id'=> $userId])->increment('usdt_num', $total)){ $this->model->rollBack(); $this->error = '5003'; return false; } $usdtNum = isset($userInfo['usdt_num'])? $userInfo['usdt_num'] : 0; $data = [ 'order_no'=> $info['order_no'], 'user_id'=> $userId, 'type'=> 6, 'pay_type'=> 1, 'change_type'=> 1, 'num'=> $total, 'total'=> 0, 'balance'=> floatval($usdtNum + $total), 'create_time'=> time(), 'update_time'=> time(), 'status'=> 1, 'mark'=>1, 'remark'=> '提币失败退还', ]; if(!$this->capitalModel->edit($data)){ $this->model->rollBack(); $this->error = '3014'; return false; } } } } }