value('token'); } public static function getWalletFrozen($userID) { return self::where('user_id', $userID)->value('frozen'); } public static function getWalletBuying($userID) { return self::where('user_id', $userID)->value('buying'); } public static function getWalletTotalChaBao($userID) { return self::where('user_id', $userID)->value('token + frozen'); } public static function getWallet($userID) { return self::where('user_id', $userID)->find(); } /** * 仅事务内使用,会附带"for update" * @param $userID * @throws Exception */ public function getWalletTX($userID) { return $this->lock(true)->where('user_id', $userID)->find(); } /** * 更新钱包余额并添加账变记录 * @param int $uid 用户ID * @param string $asset 资产类型 * @param string $amount 金额 正:表示加 负:表示减 * @param int $action 账变类型 * @return void * @throws Exception */ public function changeWalletAccount(int $uid, string $asset, string $amount, int $action, int $from_id = 0) { $available = $this->getWallet($uid); if (empty($available)) (new LedgerWalletModel())->insertGetId(['user_id' => $uid]); // 创建钱包 $frozen = ''; //冻结金额 // 账变资产模型 switch ($asset) { case Asset::USDT: $changeModel = new LedgerUsdtChangeModel(); break; case Asset::TOKEN: $changeModel = new LedgerTokenChangeModel(); break; case Asset::TEAC: $changeModel = new LedgerTeacChangeModel(); break; case Asset::SMH: $changeModel = new LedgerSmhChangeModel(); break; case Asset::FROZEN: //扣掉赠送手续费 $changeModel = new LedgerFrozenChangeModel(); break; default: throw new Exception('币种错误:' . $asset); } // 更新钱包余额 $newAmount = $this->changeWalletOnly($uid, $asset, $amount); // 创建账变记录 $insertRs = $changeModel->insert([ 'user_id' => $uid, 'from_id' => $from_id, 'change_amount' => $amount, 'present_amount' => $newAmount, 'create_time' => time(), 'action' => $action ]); if (empty($insertRs)) { throw new Exception('创建' . $asset . '账变记录失败'); } } /** * 仅更新钱包余额,没有账变 * @param int $uid 用户ID * @param string $asset 资产类型 * @param string $amount 金额 正:表示加 负:表示减 * @return string 变动后的金额 * @throws Exception */ public function changeWalletOnly(int $uid, string $asset, string $amount): string { $available = $this->getWalletTX($uid); if (empty($available)) { throw new Exception('用户资产信息不存在'); } // 金额为0的判断 $amount = bcadd($amount, 0, 6); if (bccomp($amount, '0', 6) == 0) { throw new Exception('金额变动为0'); } // 余额不足的判断 if ($amount < 0 && $available[$asset] < -$amount) { throw new Exception(Asset::getAssetName($asset) . '余额不足'); } $newAmount = bcadd($available[$asset], $amount, 6); // 新余额 $walletUpdate = [$asset => $newAmount, 'update_time' => time()]; // 更新余额 $changeRs = $this->save($walletUpdate, ['user_id' => $uid]); if (empty($changeRs)) { throw new Exception('更新' . $asset . '余额失败'); } return $newAmount; } /** * 冻结茶宝 * @param int $uid 用户ID * @param string $amount 报单金额 * @return void * @throws Exception */ public function setChangeFrozen(int $uid, string $amount, int $action, string $icn, int $from_id = 0) { $available = $this->getWallet($uid); $ledgerWalletModel = new LedgerWalletModel(); if (empty($available)) $ledgerWalletModel->insertGetId(['user_id' => $uid]); // 创建钱包 $walletUpdate = []; $result = false; //运费/手续费:扣除 if($icn == '-'){ $totalAmount = bcadd($available['token'], $available['frozen'], 6); //扣除冻结金额 if($available['frozen'] > $amount) $walletUpdate['frozen'] = bcsub($available['frozen'], $amount, 6); if($available['frozen'] <= $amount) { $walletUpdate = ['token'=> bcadd($totalAmount, -$amount, 6), 'frozen' => 0]; //添加账变记录 $subAmount = bcsub($amount, $available['frozen'], 6); $this->changeWalletAccount($uid, Asset::TOKEN, -$subAmount, LedgerTokenChangeModel::Giveaway, $from_id); } //添加冻结 $newAmount = $walletUpdate['frozen']; if($available['frozen'] > 0) $result = true; } //手续费 if($icn == '+' && $available['frozen'] < $amount){ //添加账变记录 if($available->token < $amount) throw new Exception('茶宝不足'); $sunAmount = bcsub($available->frozen, $amount, 6); //扣除的冻结金额 $chabao = bcadd($available['token'], $sunAmount, 6); $newAmount = $amount; //剩余的冻结金额 //添加冻结 $walletUpdate =['token' => $chabao, 'frozen' =>$newAmount]; $this->changeWalletAccount($uid, Asset::TOKEN, $sunAmount, LedgerTokenChangeModel::Super, $from_id); $result = true; } // 创建账变记录 if (count($walletUpdate) > 0) $ledgerWalletModel->where('user_id', $uid)->update($walletUpdate); if($result){ return (new LedgerFrozenChangeModel())->insert([ 'user_id' => $uid, 'from_id' => $from_id, 'change_amount' => $icn.$amount, 'present_amount' => $newAmount, 'create_time' => time(), 'action' => $action ]); } } /** * 发放直推USDT收益 * @param int $uid * @param string $power * @return void * @throws DbException */ public function sendUsdtProfit(int $uid, string $amount) { $ratio = (new Config())->getValue('direct_income');//直推奖励 $user = (new UserModel())->get($uid); if (empty($user) || $user['parent_id'] == 0) { return; } $parent = (new UserModel())->get($user['parent_id']); if (empty($parent)) { return; } $temp = ['拦截提醒', $uid, $amount, $amount * $ratio]; //dump($temp); // 上级算力的账变 $this->changeWalletAccount($user['parent_id'], Asset::USDT, $amount * $ratio, Action::UsdtShareBonus, $uid); } /** * 发放直推收益 * @param int $uid * @param string $power * @return void * @throws DbException */ public function sendDirectProfit(int $uid, string $power) { $user = (new UserModel())->get($uid); if (empty($user) || $user['parent_id'] == 0) { return; } $parent = (new UserModel())->get($user['parent_id']); if (empty($parent)) { return; } // 查询直推奖励比例 $directProfit = (new Config())->getValue('direct_income'); $directProfitFloat = floatval($directProfit); if (is_null($directProfit) || $directProfitFloat <= 0) { return; } $directPower = $power * $directProfitFloat; // 可获得的直推奖励(算力) if($directPower > 0){ $this->changeWalletAccount($user['parent_id'], Asset::POWER, $directPower, Action::PowerDirectAward, $uid); } // 上级算力的账变 } public function users() { return $this->hasOne(UserModel::class, 'id', 'user_id'); } public function getCreateTimeTextAttr($value, $data) { $value = $value ? $value : (isset($data['create_time']) ? $data['create_time'] : ''); return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value; } public function getUpdateTimeTextAttr($value, $data) { $value = $value ? $value : (isset($data['update_time']) ? $data['update_time'] : ''); return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value; } protected function setCreateTimeAttr($value) { return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value); } protected function setUpdateTimeAttr($value) { return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value); } }