userId = $userId; if(is_int($fundId)){ $this->fundId = $fundId; }else{ $this->fundId = $fundId->valueInt(); } $this->fundModel = FundModel::query() ->where('user_id', $userId) ->where('fund_id', $fundId) ->first(); } /** * 资金流转 * (同用户,同币种,不同账户) * * @param FUND_TYPE $to_fund_id 目标资金类型 * @param float $amount 金额(小数形式) * @param int $re_id 关联ID * @param string $re_type 关联类型 * @param string $remark 备注 * @return CirculationDto|string 成功返回DTO,失败返回错误信息 */ public function circulation(FUND_TYPE $to_fund_id, float $amount, int $re_id, string $re_type, string $remark) { # 确认货币种类一致 if (!CurrencyService::check($this->fundId, $to_fund_id->valueInt())) { return '币种不一致,禁止划转'; } # 验证金额精度 $currency = CurrencyService::getCurrencyByFundId($this->fundId); if (!$currency) { return '无法获取币种信息'; } # 验证并格式化金额精度 if (!CurrencyService::validateAmountPrecision($amount, $currency->currencyId)) { return '金额精度超出币种支持范围'; } $formattedAmount = CurrencyService::formatAmountToPrecision($amount, $currency->currencyId); if(bccomp($amount, $formattedAmount,10) != 0){ return '数值错误,精度丢失'; } if(bccomp(0, $formattedAmount,10) == 0){ return '数值错误,数值丢失'; } Logger::debug(" jine $amount , $formattedAmount"); # 实例化操作对象 Helper::check_tr(); # 先进行转账记录 $circulation_id = Circulation::handle($this->userId, $this->fundId, $to_fund_id->valueInt(), $formattedAmount, $re_id, $re_type, $remark); if (is_string($circulation_id)) { return $circulation_id; } # 进行双方的资金修改 # 先减少自己的 $re46 = User::handle($this->userId, $this->fundId, -$formattedAmount, LOG_TYPE::CIRCULATION, $circulation_id, $remark); if (is_string($re46)) { return $re46; } # 再增加自己另一个账户 $re51 = User::handle($this->userId, $to_fund_id->valueInt(), $formattedAmount, LOG_TYPE::CIRCULATION, $circulation_id, $remark); if (is_string($re51)) { return $re51; } // 获取流转记录 $circulationModel = \App\Module\Fund\Models\FundCirculationModel::find($circulation_id); if (!$circulationModel) { return '流转记录不存在'; } // 获取资金类型名称映射 $fundNames = AccountService::getFundsDesc(); // 将模型转换为DTO并返回 return CirculationDto::fromModel($circulationModel, $fundNames); } /** * 获取账户信息 * * @return FundAccountDto|null 账户DTO,如果账户不存在则返回null */ public function getAccount(): ?FundAccountDto { // 如果账户不存在,返回null if (!$this->fundModel) { return null; } // 获取资金类型名称映射 $fundNames = AccountService::getFundsDesc(); // 将模型转换为DTO return FundAccountDto::fromModel($this->fundModel, $fundNames); } /** * 获取余额 * * @return float 账户余额(小数形式) */ public function balance(): float { // 直接返回数据库中的小数值 return (float)($this->fundModel->balance ?? 0); } /** * 转账 * (不同人,同账户/同币种) * * @param int $toUserId 接收用户ID * @param float $amount 金额(小数形式) * @param string $remark 备注 * @return TransferResultDto|string 成功返回DTO,失败返回错误信息 */ public function transfer(int $toUserId, float $amount, string $remark) { # 验证金额精度 $currency = CurrencyService::getCurrencyByFundId($this->fundId); if (!$currency) { return '无法获取币种信息'; } # 验证并格式化金额精度 if (!CurrencyService::validateAmountPrecision($amount, $currency->currencyId)) { return '金额精度超出币种支持范围'; } $formattedAmount = CurrencyService::formatAmountToPrecision($amount, $currency->currencyId); if(bccomp($amount, $formattedAmount,10) != 0){ return '数值错误,精度丢失'; } if(bccomp(0, $formattedAmount,10) == 0){ return '数值错误,数值丢失'; } # 实例化操作对象 # 开启事务 DB::beginTransaction(); # 先进行转账记录 $transfer_id = Transfer::to_user( $this->userId, $this->fundId, $toUserId, $formattedAmount, $remark); if (is_string($transfer_id)) { DB::rollBack(); return $transfer_id; } # 进行双方的资金修改 # 先减少自己的 $re46 = User::handle($this->userId, $this->fundId, -$formattedAmount, LOG_TYPE::TRANSFER, $transfer_id, $remark); if (is_string($re46)) { DB::rollBack(); return $re46; } # 再增加别人的 $re51 = User::handle($toUserId, $this->fundId, $formattedAmount, LOG_TYPE::TRANSFER, $transfer_id, $remark); if (is_string($re51)) { DB::rollBack(); return $re51; } DB::commit(); // 获取转账记录 $transferModel = \App\Module\Fund\Models\FundTransferModel::find($transfer_id); if (!$transferModel) { return '转账记录不存在'; } // 获取资金类型名称映射 $fundNames = AccountService::getFundsDesc(); // 获取用户名称映射 $userNames = []; $userIds = [$this->userId, $toUserId]; $users = \App\Module\User\Models\User::whereIn('id', $userIds)->get(); foreach ($users as $user) { $userNames[$user->id] = $user->username; } // 将模型转换为DTO并返回 return TransferResultDto::fromModel($transferModel, $fundNames, $userNames); } /** * 贸易(业务关联) * 同账户/同币种,不同用户 * * @param int $toUserId 接收用户ID * @param float $amount 金额(小数形式) * @param string $transfer_type 关联类型 * @param string $transfer_id 关联ID * @param string $remark 备注 * @return TradeResultDto|string 成功返回DTO,失败返回错误信息 */ public function trade(int $toUserId, float $amount, $transfer_type, $transfer_id, string $remark) { # 验证金额精度 $currency = CurrencyService::getCurrency2ByFundId($this->fundId); if (!$currency) { return '无法获取币种信息'; } # 验证并格式化金额精度 if (!CurrencyService::validateAmountPrecision($amount, $currency->value)) { return '金额精度超出币种支持范围'; } $formattedAmount = CurrencyService::formatAmountToPrecision($amount, $currency->value); if(bccomp($amount, $formattedAmount,10) != 0){ return '数值错误,精度丢失'; } if(bccomp(0, $formattedAmount,10) == 0){ return '数值错误,数值丢失'; } # 检查事务开启 Helper::check_tr(); $full_transfer_id = $transfer_type.'-'.$transfer_id; # 先减少自己的 $re46 = User::handle($this->userId, $this->fundId, -$formattedAmount, LOG_TYPE::TRADE, $full_transfer_id, $remark); if (is_string($re46)) { \UCore\Trace::addData('error', $re46); return $re46; } # 再增加别人的 $re51 = User::handle($toUserId, $this->fundId, $formattedAmount, LOG_TYPE::TRANSFER, $full_transfer_id, $remark); if (is_string($re51)) { \UCore\Trace::addData('error', $re51); return $re51; } // 获取资金类型名称映射 $fundNames = AccountService::getFundsDesc(); // 获取用户名称映射 $userNames = []; $userIds = [$this->userId, $toUserId]; $users = \App\Module\User\Models\User::whereIn('id', $userIds)->get(); foreach ($users as $user) { $userNames[$user->id] = $user->username; } // 创建DTO并返回(传入原始小数金额) return TradeResultDto::create( $this->userId, $toUserId, $this->fundId, $amount, $transfer_type, $transfer_id, $remark, $fundNames, $userNames ); } /** * Admin 资金操作 * * @param int $admin_id * @param FUND_TYPE $fund_id * @param float $fund_fee 金额(小数形式) * @param $remark * @return FundAdminDto|string 成功返回DTO,失败返回错误信息 */ public function admin_operate(int $admin_id, FUND_TYPE $fund_id, float $fund_fee, $remark) { # 验证金额精度 $currency = CurrencyService::getCurrencyByFundId($fund_id->valueInt()); if (!$currency) { return '无法获取币种信息'; } # 验证并格式化金额精度 if (!CurrencyService::validateAmountPrecision($fund_fee, $currency->currencyId)) { return '金额精度超出币种支持范围'; } $formattedFundFee = CurrencyService::formatAmountToPrecision($fund_fee, $currency->currencyId); $data = [ 'total_fee' => $formattedFundFee, 'status' => 1, 'user_id' => $this->userId, 'fund_id' => $fund_id->valueInt(), 'admin_id' => $admin_id, 'create_time' => time(), 'remark' => $remark ]; # 启动事务 DB::beginTransaction(); # 写日志 $fund_admin = new FundAdminModel(); $fund_admin->setData($data); if ($fund_admin->save() === false) { DB::rollBack(); return '_Model-error'; } # 进行资金操作 $re = \App\Module\Fund\Logic\User::handle($this->userId, $fund_id->value, $formattedFundFee, \App\Module\Fund\Enums\LOG_TYPE::ADMIN, $fund_admin->id, $remark); if (is_string($re)) { DB::rollBack(); return $re; } DB::commit(); // 获取资金类型名称映射 $fundNames = AccountService::getFundsDesc(); // 将模型转换为DTO并返回 return FundAdminDto::fromModel($fund_admin, $fundNames); } }