field('id,stock_code,min_price,stock_type,stock_name,tag,cycle,rate,stock_info,open_status')->append(['stock_type_text', 'open_status_text', 'stock_type_en_text', 'open_status_en_text'])->orderRaw($orderString)->order('sort', 'asc')->page($param['page'], $param['limit'])->select(); $total = PreFundStockModel::where($where)->count(); return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => $total]); } catch (\Exception $exception) { return $this->toData('400', 'System error', [$exception->getMessage()]); } } // 基金详情 public function detail($param): array { try { if (empty($param['id']) || !is_numeric($param['id'])) { return $this->toData('1', 'Params error', []); } $fund = PreFundStockModel::where('id', $param['id'])->where('is_delete', PreFundStockModel::IS_DELETE_NO)->find(); if (empty($fund)) { return $this->toData('1', 'Params error', []); } $fund->product_file = json_decode($fund->product_file, true); $fund->current_manager = json_decode($fund->current_manager, true); return $this->toData('0', 'SUCCESS', ['data' => $fund, 'interest' => $fund->show_interest]); } catch (\Exception $exception) { return $this->toData('400', 'System error', [$exception->getMessage()]); } } // 基金历史走势 public function history(array $param): array { try { if (empty($param['stock_code']) || !is_string($param['stock_code'])) { return $this->toData('1', 'Params error', []); } if (empty($param['type']) || !in_array($param['type'], [1, 2, 3])) { $param['type'] = 1; } $historyData = HistoryFundStockModel::where('stock_code', $param['stock_code'])->find(); if (empty($historyData)) { return $this->toData('1', 'Params error', []); } $history = []; $historyInfo = json_decode($historyData->history_info, true); $start = new DateTime($historyData->start_date); $end = new DateTime($historyData->end_date); switch ($param['type']) { case 1: //日 $history = $historyInfo; break; case 2: //月 // 创建 DateInterval 对象,表示一个月的时间间隔 $interval = new DateInterval('P1M'); // 创建 DatePeriod 对象,表示两个日期之间的月份 $period = new DatePeriod($start, $interval, $end); foreach ($period as $date) { $month = $date->format('Y-m'); $firstDay = new DateTime("$month-01"); $nextMonth = clone $firstDay; $nextMonth->modify('+1 month'); $lastDay = $nextMonth->modify('-1 day'); $monthlastDay = $lastDay->format('Y-m-d'); if ($lastDay > $end) { $monthlastDay = $end->format('Y-m-d'); } $history[$month] = $historyInfo[$monthlastDay]; } break; case 3: //年 $currentDate = clone $start; $startYear = $currentDate->format('Y'); $currentYear = new DateTime("$startYear-01-01"); while ($currentYear <= $end) { $lastDayOfYear = new DateTime($currentYear->format('Y') . "-12-31"); $lastDayOfYearStr = $lastDayOfYear->format('Y-m-d'); if ($lastDayOfYear > $end) { $lastDayOfYearStr = $end->format('Y-m-d'); } $history[$currentYear->format('Y')] = $historyInfo[$lastDayOfYearStr]; $currentYear->modify('+1 year'); } break; } $year = []; if ($param['type'] == 3) { $year = $history; } else { $currentDate = clone $start; $startYear = $currentDate->format('Y'); $currentYear = new DateTime("$startYear-01-01"); while ($currentYear <= $end) { $lastDayOfYear = new DateTime($currentYear->format('Y') . "-12-31"); $lastDayOfYearStr = $lastDayOfYear->format('Y-m-d'); if ($lastDayOfYear > $end) { $lastDayOfYearStr = $end->format('Y-m-d'); } $year[$currentYear->format('Y')] = $historyInfo[$lastDayOfYearStr]; $currentYear->modify('+1 year'); } } $refer = PreFundStockReferModel::select(); $referResult = []; foreach ($refer as $v) { $referResult[$v['name']][$v['year']] = $v['rate']; } return $this->toData('0', 'SUCCESS', ['data' => $history, 'year' => $year, 'refer' => $referResult]); } catch (\Exception $exception) { return $this->toData('400', 'System error', [$exception->getMessage()]); } } // 下单 public function order($param, $userId) { try { // 需要完成实名认证之后才能下单 $user = UserModel::where('user_id', $userId)->find(); if (empty($user) || $user->is_real != 1) { return $this->toData('405', 'Only after completing real-name authentication can you place an order.'); } if (empty($userId)) { return $this->toData('1', 'Login fail'); } if (empty($param['id']) || !is_numeric($param['id'])) { return $this->toData('1', 'Params error2', []); } $fund = PreFundStockModel::where('id', $param['id']) ->where('open_status', PreFundStockModel::OPEN_STATUS_HAD) ->where('is_delete', PreFundStockModel::IS_DELETE_NO) ->whereTime('start_time', '<=', date('Y-m-d H:i:s')) ->whereTime('end_time', '>=', date('Y-m-d H:i:s')) ->find(); if (empty($fund)) { return $this->toData('1', 'Params error3', []); } // 下单参数 if (empty($param['amount']) || !is_numeric($param['amount']) || ceil($param['amount']) != $param['amount'] || $param['amount'] <= 0) { return $this->toData('1', 'Params error', []); } if ($param['amount'] < $fund->min_price) { return $this->toData('1', 'Params num error4', []); } $amount = $param['amount']; // 计算手续费 $purchaseFee = FeeSettingModel::where('market_type', StockMarketModel::STOCK_MARKET_FUND)->value('purchase_fee'); if (empty($purchaseFee)) { $purchaseFee = 0; $fee = 0; } else { $purchaseFee = number_format($purchaseFee, 18, '.', ''); $fee = bcmul($amount, $purchaseFee, 18); } Db::startTrans(); // 生成订单 $orderNo = $this->generateOrderNumber(20); $order = new UserFundPreStockOrderModel; $order->user_id = $userId; $order->pre_stock_id = $fund->id; $order->status = UserFundPreStockOrderModel::STATUS_ONE; $order->order_no = $orderNo; $order->amount = $amount; $order->phase_count = $fund->phase_count; $order->stock_rate = $fund->rate; $order->stock_cycle_type = $fund->cycle_type; $order->stock_cycle = $fund->cycle; $order->fee = $fee; $order->fee_rate = $purchaseFee; // 手续费比率 $bool = $order->save(); if (!$bool) { Db::rollback(); return $this->toData('1', 'create fund order error', []); } // 扣除用户资产 $userStockName = (new UserStockFundModel())->getName(); $beforeAmount = Db::name($userStockName)->where('stock_id', 'USD')->where('user_id', $userId)->value('usable_num'); if ($beforeAmount < $amount) { Db::rollback(); return $this->toData('1', 'assert not enough', []); } $updateNum = Db::name($userStockName)->where('stock_id', 'USD')->where('user_id', $userId) ->where('usable_num', '>=', $amount)->dec('usable_num', $amount) ->update(['update_time' => date('Y-m-d H:i:s')]); if ($updateNum <= 0) { Db::rollback(); return $this->toData('1', 'Update user amount error', []); } // 生成流水 $userStockLog = new UserStockFundLogModel(); $userStockLog->user_id = $userId; $userStockLog->change_type = 3; $userStockLog->stock_id = 'USD'; $userStockLog->before_num = $beforeAmount; $userStockLog->change_num = '-' . $amount; $userStockLog->order_id = $orderNo; $userStockLog->create_time = date('Y-m-d H:i:s'); $userStockLog->update_time = date('Y-m-d H:i:s'); $updateNum2 = $userStockLog->save(); if ($updateNum2 <= 0) { Db::rollback(); return $this->toData('1', 'create user log error', []); } // 扣除手续费 if ($fee > 0) { $beforeFee = Db::name($userStockName)->where('stock_id', 'USD')->where('user_id', $userId)->value('usable_num'); if ($beforeFee < $fee) { Db::rollback(); return $this->toData('1', 'assert not enough', []); } $updateNum = Db::name($userStockName)->where('stock_id', 'USD')->where('user_id', $userId) ->where('usable_num', '>=', $fee)->dec('usable_num', $fee) ->inc('frozen_num', $fee) ->update(['update_time' => date('Y-m-d H:i:s')]); if ($updateNum <= 0) { Db::rollback(); return $this->toData('1', 'Update user amount error', []); } // 生成流水 $userStockLog = new UserStockFundLogModel; $userStockLog->user_id = $userId; $userStockLog->change_type = 14; //扣手续费 $userStockLog->stock_id = 'USD'; $userStockLog->before_num = $beforeFee; $userStockLog->change_num = '-' . $fee; $userStockLog->order_id = $orderNo; $userStockLog->create_time = date('Y-m-d H:i:s'); $userStockLog->update_time = date('Y-m-d H:i:s'); $updateNum3 = $userStockLog->save(); if ($updateNum3 <= 0) { Db::rollback(); return $this->toData('1', 'create user fee log error', []); } } // 生成基金返款记录 $userStockFundInterestReceipt = new UserStockFundInterestReceiptModel; $userStockFundInterestReceipt->user_id = $userId; $userStockFundInterestReceipt->order_id = $order->id; $userStockFundInterestReceipt->pre_stock_id = $fund->id; $userStockFundInterestReceipt->order_no = $this->generateOrderNumber(20); $userStockFundInterestReceipt->capital = $amount; $userStockFundInterestReceipt->interest = bcmul($amount, $fund->rate / 100, 18); $userStockFundInterestReceipt->phase_time = 1; $userStockFundInterestReceipt->unit = 'USD'; $currentDate = new DateTime(); $addDay = $fund->cycle + 1; $currentDate->modify("+$addDay days"); $userStockFundInterestReceipt->return_date = $currentDate->format('Y-m-d'); $userStockFundInterestReceiptBool = $userStockFundInterestReceipt->save(); if (!$userStockFundInterestReceiptBool) { Db::rollback(); return $this->toData('1', 'update fund interest error', []); } //更新基金 已购买金额 $fundHadNum = PreFundStockModel::where('id', $fund->id)->inc('had_get_price', $amount)->update(['update_time' => date('Y-m-d H:i:s')]); if ($fundHadNum <= 0) { Db::rollback(); return $this->toData('1', 'Update fund had_get_price error', []); } Db::commit(); return $this->toData('0', 'SUCCESS', []); } catch (\Exception $exception) { return $this->toData('0', 'The system is busy. Please try again later.', [$exception->getMessage()]); } } public function userFund($param, $userId) { try { if (empty($param['page']) || !is_numeric($param['page']) || empty($param['limit']) || !is_numeric($param['limit'])) { $param['page'] = 1; $param['limit'] = 10; } $oderTableName = (new UserFundPreStockOrderModel())->getName(); $oderTableName = 'bot_' . $oderTableName; $total = UserFundPreStockOrderModel::where("user_id", $userId)->count(); $rows = UserFundPreStockOrderModel::where($oderTableName . ".user_id", $userId)->with('interest_arr')->withJoin(['fund' => ['stock_name', 'cycle', 'rate', 'stock_info', 'stock_type']])->append(['status_en_text'])->order('status', 'asc')->order('id', 'desc')->page($param['page'], $param['limit'])->select()->toArray(); foreach ($rows as &$v) { $capitalArr = array_column($v['interest_arr'], 'capital'); $interestArr = array_column($v['interest_arr'], 'interest'); $v['capital'] = array_sum($capitalArr); $v['interest'] = array_sum($interestArr); $v['fund']['stock_type_en_text'] = PreFundStockModel::$stockTypeEnList[$v['fund']['stock_type']]; } return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => $total]); } catch (\Exception $exception) { return $this->toData('400', 'System error', [$exception->getMessage()]); } } }