// +---------------------------------------------------------------------- namespace App\Services\Common; use App\Models\AcceptorModel; use App\Models\AccountLogModel; use App\Models\BalanceLogModel; use App\Models\MemberModel; use App\Models\MerchantModel; use App\Services\Api\FinanceService; use App\Services\Api\MessageService; use App\Services\BaseService; use App\Services\RedisService; use App\Services\WalletService; use Illuminate\Support\Facades\DB; /** * 承兑商管理-服务类 * @author laravel开发员 * @since 2020/11/11 * @package App\Services\Common */ class BalanceLogService extends BaseService { // 静态对象 protected static $instance = null; /** * 构造函数 * @author laravel开发员 * @since 2020/11/11 */ public function __construct() { $this->model = new BalanceLogModel(); } /** * 静态入口 * @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 = 10, $field = []) { $query = $this->getQuery($params); $list = $query->select($field ? $field : ['a.*', 'b.username','b.trc_url as user_trc_url', 'b.nickname','c.user_id as merchant_uid','d.user_id as acceptor_uid']) ->orderBy('a.status','asc') ->orderBy('a.create_time','desc') ->orderBy('a.pay_at','desc') ->paginate($pageSize > 0 ? $pageSize : 9999999); $list = $list ? $list->toArray() : []; if ($list) { foreach ($list['data'] as &$item) { $item['create_time'] = datetime($item['create_time'],'Y-m-d H:i:s'); $item['pay_img'] = isset($item['pay_img'])?get_image_url($item['pay_img']):''; $item['trc_url'] = $item['trc_url']?$item['trc_url'] : $item['user_trc_url']; if($item['user_type'] == 1){ $item['uid'] = $item['user_id']; $item['account'] = isset($item['nickname'])&& $item['nickname']?$item['nickname'].(isset($item['username'])?' '.$item['username']:'') : $item['user_id']; }else if($item['user_type'] == 2){ $item['uid'] = isset($item['merchant']['user_id'])&& $item['merchant']? $item['merchant']['user_id'] : 0; $item['account'] = isset($item['merchant']['nickname'])&& $item['merchant']?$item['merchant']['nickname'].(isset($item['merchant']['mobile'])?' '.$item['merchant']['mobile']:'') : $item['merchant_uid']; }else if($item['user_type'] == 3){ $item['uid'] = isset($item['acceptor']['user_id'])&& $item['acceptor']? $item['acceptor']['user_id'] : 0; $item['account'] = isset($item['acceptor']['nickname'])&& $item['acceptor']?$item['acceptor']['nickname'].(isset($item['acceptor']['mobile'])?' '.$item['acceptor']['mobile']:'') : $item['acceptor_uid']; } } } return [ 'pageSize' => $pageSize, 'total' => isset($list['total']) ? $list['total'] : 0, 'list' => isset($list['data']) ? $list['data'] : [] ]; } /** * 查询构造 * @param $params * @return \Illuminate\Database\Eloquent\Builder */ public function getQuery($params) { $where = ['a.mark' => 1]; return $this->model->with(['member','acceptor','merchant','payment']) ->from('balance_logs as a') ->leftJoin('member as b', function($join) { $join->on('b.id','=', 'a.user_id')->where('a.user_type',1); }) ->leftJoin('merchant as c', function($join) { $join->on('c.id','=', 'a.user_id')->where('a.user_type',2); }) ->leftJoin('acceptor as d', function($join) { $join->on('d.id','=', 'a.user_id')->where('a.user_type',3); }) ->where($where) ->where(function ($query) use ($params) { $userType = isset($params['user_type'])? intval($params['user_type']) : 1; $kw = isset($params['keyword']) ? trim($params['keyword']) : ''; if ($kw) { if($userType == 3){ $query->where('d.name', 'like', "%{$params['keyword']}%") ->orWhere('d.mobile', 'like', "%{$params['keyword']}%"); }else if($userType == 2){ $query->where('c.name', 'like', "%{$params['keyword']}%") ->orWhere('c.mobile', 'like', "%{$params['keyword']}%"); }else if($userType == 1){ $query->where('b.nickname', 'like', "%{$params['keyword']}%") ->orWhere('b.username', 'like', "%{$params['keyword']}%"); }else{ $query->where('b.nickname', 'like', "%{$params['keyword']}%") ->orWhere('b.username', 'like', "%{$params['keyword']}%") ->orWhere('c.name', 'like', "%{$params['keyword']}%") ->orWhere('c.mobile', 'like', "%{$params['keyword']}%") ->orWhere('d.name', 'like', "%{$params['keyword']}%") ->orWhere('d.mobile', 'like', "%{$params['keyword']}%"); } } }) ->where(function ($query) use($params){ // 日期 $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)); } $orderNo = isset($params['order_no'])? trim($params['order_no']) : ''; if($orderNo){ $query->where('a.order_no', 'like', "%{$orderNo}%"); } $trcUrl = isset($params['trc_url'])? trim($params['trc_url']) : ''; if($trcUrl){ $query->where('a.trc_url', '=', $trcUrl); } $hash = isset($params['hash'])? trim($params['hash']) : ''; if($hash){ $query->where('a.trc_url', '=', $hash); } $orderNo = isset($params['order_no'])? trim($params['order_no']) : ''; if($orderNo){ $query->where('a.order_no', 'like', "%{$orderNo}%"); } $userType = isset($params['user_type'])? $params['user_type'] : 0; if ($userType) { $query->where('a.user_type', $userType); } $payType = isset($params['pay_type'])? $params['pay_type'] : 0; if ($payType) { $query->where('a.pay_type', $payType); } $payStatus = isset($params['pay_status'])? $params['pay_status'] : 0; if ($payStatus) { $query->where('a.pay_status', $payStatus); } $type = isset($params['type'])? $params['type'] : 0; if (is_array($type)) { $query->whereIn('a.type', $type); } else if($type){ $query->where('a.type', $type); } $coinType = isset($params['coin_type'])? $params['coin_type'] : 0; if (is_array($coinType)) { $query->whereIn('a.coin_type', $coinType); } else if($coinType){ $query->where('a.coin_type', $coinType); } $status = isset($params['status'])? $params['status'] : 0; if (is_array($status)) { $query->whereIn('a.status', $status); } else if($status){ $query->where('a.status', $status); } }); } /** * 统计 * @param $params * @return array */ public function count($params) { $query = $this->getQuery($params); $count = $query->count('a.id'); $total = $query->sum('a.actual_money'); return [ 'count' => $count, 'total' => $total ]; } /** * 充值审核 * @param $params * @return bool */ public function rechargeAuth($params) { $id = isset($params['id'])? $params['id'] : 0; $checkStatus = isset($params['status'])? $params['status'] : 0; $remark = isset($params['audit_remark'])? trim($params['audit_remark']) : ''; $payImg = isset($params['pay_img'])? trim($params['pay_img']) : ''; if(!in_array($checkStatus,[2,3])){ $this->error = 1073; return false; } $info = $this->model->with(['member','merchant','acceptor'])->where(['id'=> $id,'mark'=>1])->first(); $type = isset($info['type'])? $info['type'] : 0; $userType = isset($info['user_type'])? $info['user_type'] : 0; $coinType = isset($info['coin_type'])? $info['coin_type'] : 0; $payType = isset($info['pay_type'])? $info['pay_type'] : 0; $accountId = isset($info['user_id'])? $info['user_id'] : 0; $money = isset($info['money'])? $info['money'] : 0; $actualMoney = isset($info['actual_money'])? $info['actual_money'] : 0; $status = isset($info['status'])? $info['status'] : 0; if($id<=0 || empty($info) || $accountId<=0){ $this->error = 4001; return false; } if($status != 1){ $this->error = 4002; return false; } if($type != 1){ $this->error = 1031; return false; } $cacheKey ="caches:recharge:lock_{$id}"; if(RedisService::get($cacheKey)){ $this->error = 1034; return false; } // 绑定的用户ID $userId = $accountId; $userInfo = isset($info['member'])? $info['member'] : []; $balance = isset($userInfo['usdt'])? $userInfo['usdt'] : 0; if($userType == 2){ $userInfo = isset($info['merchant'])? $info['merchant'] : []; $userId = isset($userInfo['user_id'])? $userInfo['user_id'] : 0; $balance = isset($userInfo['usdt'])? $userInfo['usdt'] : 0; }else if($userType == 3){ $userInfo = isset($info['acceptor'])? $info['acceptor'] : []; $userId = isset($userInfo['user_id'])? $userInfo['user_id'] : 0; $balance = isset($userInfo['quota'])? $userInfo['quota'] : 0; } if(empty($userInfo)){ $this->error = 4004; return false; } // 审核处理 RedisService::set($cacheKey, true); $updateData = ['status'=> $checkStatus,'audit_remark'=> $remark,'update_time'=> time()]; DB::beginTransaction(); if(!$this->model->where(['id'=> $id])->update($updateData)){ DB::rollBack(); $this->error = 1072; RedisService::clear($cacheKey); return false; } // 审核通过到账处理 $dateTime = date('Y-m-d H:i:s'); $coinTypes = [1=>'USDT余额',2=>'星豆余额',3=>'交易额度']; $accountTypes = [1=>'会员账户',2=>'商家账户',3=>'承兑商账户']; $coinName = isset($coinTypes[$coinType])? $coinTypes[$coinType] : '账户'; $accountName = isset($accountTypes[$userType])? $accountTypes[$userType] : '会员账户'; if($checkStatus == 2) { // 线下交易 if($payType == 30){ if(!in_array($userType,[1,3]) && !in_array($coinType,[1,6])){ DB::rollBack(); $this->error = 1021; RedisService::clear($cacheKey); return false; } // USDT入账 if($userType == 1 && $coinType == 1){ $updateData = ['usdt' => DB::raw("usdt + {$actualMoney}"),'update_time'=>time()]; if (!MemberModel::where(['id' => $accountId])->update($updateData)){ DB::rollBack(); $this->error = 1072; RedisService::clear($cacheKey); return false; } } // 交易额度入账 else if($userType == 3 && $coinType == 6){ $updateData = ['quota' => DB::raw("quota + {$actualMoney}"),'update_time'=>time()]; if (!AcceptorModel::where(['id' => $accountId])->update($updateData)){ DB::rollBack(); $this->error = 1072; RedisService::clear($cacheKey); return false; } } // 账户明细 $log = [ 'user_id' => $accountId, 'source_id' => 0, 'source_order_no' => $info['order_no'], 'type' => 5, 'coin_type' => $coinType, 'user_type'=> $userType, 'money' => $money, 'actual_money' => $actualMoney, 'balance' => $balance, 'create_time' => time(), 'update_time' => time(), 'remark' => "{$coinName}充值", 'status' => 1, 'mark' => 1, ]; if(!AccountLogModel::insertGetId($log)){ DB::rollBack(); $this->error = 2029; RedisService::clear($cacheKey); return false; } }else{ DB::rollBack(); $this->error = 1021; RedisService::clear($cacheKey); return false; } $title = "{$coinName}充值审核成功通知"; $message = "您的充值申请在{$dateTime}UTC+8审核成功,明细如下:\n单号:{$info['order_no']}\n账户:{$accountName}\n金额:{$money}\n到账:{$actualMoney}\n审核状态:成功\n审核说明:{$remark}"; }else{ $title = "{$coinName}充值审核失败通知"; $message = "您的充值申请在{$dateTime}UTC+8审核失败,明细如下:\n单号:{$info['order_no']}\n账户:{$accountName}\n金额:{$money}\n到账:{$actualMoney}\n审核状态:未通过\n审核说明:{$remark}"; } // 消息通知 MessageService::make()->pushMessage($userId, $title, $message, 3); DB::commit(); $this->error = 1071; return true; } /** * 提现审核 * @param $params * @return bool */ public function withdrawAuth($params) { $id = isset($params['id'])? $params['id'] : 0; $checkStatus = isset($params['status'])? $params['status'] : 0; $remark = isset($params['audit_remark'])? trim($params['audit_remark']) : ''; $payImg = isset($params['pay_img'])? trim($params['pay_img']) : ''; if(!in_array($checkStatus,[2,3])){ $this->error = 1073; return false; } $info = $this->model->with(['member','merchant','acceptor'])->where(['id'=> $id,'mark'=>1])->first(); $type = isset($info['type'])? $info['type'] : 0; $userType = isset($info['user_type'])? $info['user_type'] : 0; $coinType = isset($info['coin_type'])? $info['coin_type'] : 0; $payType = isset($info['pay_type'])? $info['pay_type'] : 0; $accountId = isset($info['user_id'])? $info['user_id'] : 0; $money = isset($info['money'])? $info['money'] : 0; $actualMoney = isset($info['actual_money'])? $info['actual_money'] : 0; $fee = isset($info['fee'])? $info['fee'] : 0; $status = isset($info['status'])? $info['status'] : 0; if($id<=0 || empty($info) || $accountId<=0){ $this->error = 4001; return false; } if($status != 1){ $this->error = 4002; return false; } if($type != 2){ $this->error = 1031; return false; } $cacheKey ="caches:withdraw:lock_{$id}"; if(RedisService::get($cacheKey)){ $this->error = 1034; return false; } // 绑定的用户ID $userId = $accountId; $userInfo = isset($info['member'])? $info['member'] : []; $balance = isset($userInfo['usdt'])? $userInfo['usdt'] : 0; if($userType == 2){ $userInfo = isset($info['merchant'])? $info['merchant'] : []; $userId = isset($userInfo['user_id'])? $userInfo['user_id'] : 0; $balance = isset($userInfo['usdt'])? $userInfo['usdt'] : 0; }else if($userType == 3){ $userInfo = isset($info['acceptor'])? $info['acceptor'] : []; $userId = isset($userInfo['user_id'])? $userInfo['user_id'] : 0; $balance = isset($userInfo['quota'])? $userInfo['quota'] : 0; } if(empty($userInfo)){ $this->error = 4004; return false; } // 审核处理 RedisService::set($cacheKey, true); DB::beginTransaction(); // 审核通过到账处理 $dateTime = date('Y-m-d H:i:s'); $accountTypes = [1=>'会员账户',2=>'商家账户',3=>'承兑商账户']; $coinName = 'USDT余额'; if($userType == 2 && $coinType==1){ $coinName = 'USDT佣金'; }else if($userType == 3 && $coinType==1){ $coinName = 'USDT佣金'; }else if($userType == 3 && $coinType==6){ $coinName = '交易额度'; } $accountName = isset($accountTypes[$userType])? $accountTypes[$userType] : '会员账户'; if($checkStatus == 2) { // USDT链上打款 $hash = ''; if($payType == 20){ $trcUrl = isset($userInfo['trc_url'])? $userInfo['trc_url'] : ''; if(empty($trcUrl)){ DB::rollBack(); $this->error = 4005; RedisService::clear($cacheKey); return false; } $result = WalletService::make()->usdtTrcTransfer($trcUrl, $actualMoney); $hash = isset($result['txId']) ? $result['txId'] : ''; if(empty($hash)){ DB::rollBack(); $this->error = 4005; RedisService::clear($cacheKey); return false; } $payAddress = isset($result['address']) ? $result['address'] : ''; $updateData = ['status'=>2,'audit_remark'=>$remark,'pay_img'=> get_image_path($payImg),'hash' => $hash, 'wallet_url' => $payAddress,'pay_status'=>20,'pay_at'=> $dateTime, 'update_time' => time()]; if(!$this->model->where(['id'=> $id])->update($updateData)){ DB::rollBack(); $this->error = 4006; RedisService::clear($cacheKey); return false; } } // 线下打款 else if($payType == 30){ $updateData = ['status'=> 2,'pay_status'=>20,'pay_at'=>$dateTime,'pay_img'=> get_image_path($payImg),'audit_remark'=> $remark,'update_time'=> time()]; if(!$this->model->where(['id'=> $id])->update($updateData)){ DB::rollBack(); $this->error = 1072; RedisService::clear($cacheKey); return false; } }else{ DB::rollBack(); $this->error = 1021; RedisService::clear($cacheKey); return false; } // 平台手续费明细 if($fee>0){ $log = [ 'user_id' => 0, 'source_id' => $accountId, 'source_order_no' => $info['order_no'], 'type' => 5, 'coin_type' => $coinType, 'user_type' => 4, 'money' => $fee, 'actual_money' => $fee, 'balance' => 0, 'create_time' => time(), 'update_time' => time(), 'hash' => $hash, 'remark' => "{$coinName}提现", 'status' => 1, 'mark' => 1, ]; if(!AccountLogModel::insertGetId($log)){ DB::rollBack(); $this->error = 2029; RedisService::clear($cacheKey); return false; } FinanceService::make()->saveLog(0, $fee, 1); } $title = "{$coinName}提现审核成功通知"; $message = "您的提现申请在{$dateTime}UTC+8审核成功,明细如下:\n单号:{$info['order_no']}\n账户:{$accountName}\n提现金额:{$money}\n到账:{$actualMoney}\n审核状态:审核成功\n审核说明:{$remark}"; } // 审核失败驳回退款 else{ if(!in_array($userType,[1,2,3]) && !in_array($coinType,[1,6])){ DB::rollBack(); $this->error = 1021; RedisService::clear($cacheKey); return false; } $updateData = ['status'=> 3,'pay_img'=> get_image_path($payImg),'audit_remark'=> $remark,'update_time'=> time()]; if(!$this->model->where(['id'=> $id])->update($updateData)){ DB::rollBack(); $this->error = 1072; RedisService::clear($cacheKey); return false; } // 会员:USDT驳回入账 if($userType == 1 && $coinType == 1){ $balance = isset($userInfo['usdt'])? $userInfo['usdt'] : 0; $updateData = ['usdt' => DB::raw("usdt + {$money}"),'update_time'=>time()]; if (!MemberModel::where(['id' => $accountId])->update($updateData)){ DB::rollBack(); $this->error = 1072; RedisService::clear($cacheKey); return false; } } // 商家:佣金入账 else if($userType == 2 && $coinType == 1){ $balance = isset($userInfo['usdt'])? $userInfo['usdt'] : 0; $updateData = ['usdt' => DB::raw("usdt + {$money}"),'update_time'=>time()]; if (!MerchantModel::where(['id' => $accountId])->update($updateData)){ DB::rollBack(); $this->error = 1072; RedisService::clear($cacheKey); return false; } } // 承兑商:佣金入账 else if($userType == 3 && $coinType == 1){ $balance = isset($userInfo['usdt'])? $userInfo['usdt'] : 0; $updateData = ['usdt' => DB::raw("usdt + {$money}"),'update_time'=>time()]; if (!AcceptorModel::where(['id' => $accountId])->update($updateData)){ DB::rollBack(); $this->error = 1072; RedisService::clear($cacheKey); return false; } } // 承兑商:交易额度入账 else if($userType == 3 && $coinType == 6){ $balance = isset($userInfo['quota'])? $userInfo['quota'] : 0; $updateData = ['quota' => DB::raw("quota + {$money}"),'update_time'=>time()]; if (!AcceptorModel::where(['id' => $accountId])->update($updateData)){ DB::rollBack(); $this->error = 1072; RedisService::clear($cacheKey); return false; } } // 账户明细 $log = [ 'user_id' => $accountId, 'source_id' => 0, 'source_order_no' => $info['order_no'], 'type' => 5, 'coin_type' => $coinType, 'user_type'=> $userType, 'money' => $money, 'actual_money' => $money, 'balance' => $balance, 'create_time' => time(), 'update_time' => time(), 'remark' => "{$coinName}提现驳回", 'status' => 1, 'mark' => 1, ]; if(!AccountLogModel::insertGetId($log)){ DB::rollBack(); $this->error = 2029; RedisService::clear($cacheKey); return false; } $title = "{$coinName}提现审核失败通知"; $message = "您的提现申请在{$dateTime}UTC+8审核失败,提现金额已退回对应账户,明细如下:\n单号:{$info['order_no']}\n账户:{$accountName}\n提现金额:{$money}\n到账:{$actualMoney}\n审核状态:未通过\n审核说明:{$remark}"; } // 消息通知 MessageService::make()->pushMessage($userId, $title, $message, 3); DB::commit(); $this->error = 1071; return true; } }