toData('1', '分页参数错误'); } $where = []; // 未删除 $where[] = [ 'is_delete', '=', PreFundStockModel::IS_DELETE_NO ]; // 基金号 if (!empty($param['stock_code']) && is_string($param['stock_code'])) { $where[] = [ 'stock_code', '=', $param['stock_code'] ]; } $query = PreFundStockModel::where($where)->withJoin(['history' => ['stock_code', 'start_date', 'end_date', 'start_point', 'end_point']])->order('id', 'desc'); $totalQuery = PreFundStockModel::where($where)->order('id', 'desc'); if (!empty($param['open_status']) && in_array($param['open_status'], PreFundStockModel::$openStatusList)) { $query = $query->where('open_status', $param['open_status']); $totalQuery = $totalQuery->where('open_status', $param['open_status']); } $list = $query->append(['stock_type_text', 'open_status_text'])->order('id', 'desc')->page($param['page'], $param['limit'])->select(); $total = $totalQuery->order('id', 'desc')->count(); $rows = []; if (!$list->isEmpty()) { $rows = $list->toArray(); foreach ($rows as $key => $item) { $rows[$key]['product_file'] = json_decode($item['product_file'], true); $rows[$key]['current_manager'] = json_decode($item['current_manager'], true); } } return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => $total, 'extend' => [ 'open_status_list' => PreFundStockModel::$openStatusList, 'stock_type_list' => PreFundStockModel::$stockTypeList, 'interest_type_list' => PreFundStockModel::$interestTypeList, 'cycle_type_list' => PreFundStockModel::$cycleTypeList, 'symbol' => 'USD' ]]); } catch (\Exception $exception) { return $this->toData('1', '系统繁忙', [$exception->getMessage()]); } } // 历史走势 public function history($param) { try { if (empty($param['stock_code'])) { return $this->toData('1', '基本代码 无效'); } $history = HistoryFundStockModel::where('stock_code', $param['stock_code'])->value('history_info'); $history = json_decode($history, true); return $this->toData('0', 'SUCCESS', ['history_info' => $history]); } catch (\Exception $exception) { return $this->toData('1', '系统繁忙', [$exception->getMessage()]); } } // 新增 public function add($param) { try { // 基金代码 if (empty($param['stock_code']) || !is_string($param['stock_code'])) { return $this->toData('1', '基金代码 无效'); } // 基金名称 if (empty($param['stock_name']) || !is_string($param['stock_name'])) { return $this->toData('1', '基金名称 无效'); } // 基金类型 if (empty($param['stock_type']) || !in_array($param['stock_type'], array_keys(PreFundStockModel::$stockTypeList))) { return $this->toData('1', '基金类型 无效'); } // 返利类型 if (empty($param['interest_type']) || !in_array($param['interest_type'], array_keys(PreFundStockModel::$interestTypeList))) { return $this->toData('1', '返利类型 无效'); } // 周期单位 if (empty($param['cycle_type']) || !in_array($param['cycle_type'], array_keys(PreFundStockModel::$cycleTypeList))) { return $this->toData('1', '返利类型 无效'); } // 收益率 两位小数 if (empty($param['rate']) || !is_numeric($param['rate']) || $param['rate'] <= 0) { return $this->toData('1', '基金收益率 无效'); } // 基金周期 if (empty($param['cycle']) || !is_numeric($param['cycle']) || $param['cycle'] <= 0) { return $this->toData('1', '基金周期 无效'); } // 最低申购价格 if (empty($param['min_price']) || !is_numeric($param['min_price']) || $param['min_price'] <= 0) { return $this->toData('1', '最低申购金额 无效'); } // 开始认购时间 if (empty($param['start_time']) || !is_string($param['start_time'])) { return $this->toData('1', '开始认购时间 无效'); } // 认购结束时间 if (empty($param['end_time']) || !is_string($param['end_time'])) { return $this->toData('1', '认购结束时间 无效'); } // 基金logo if (empty($param['logo']) || !is_string($param['logo'])) { return $this->toData('1', '基金logo 无效'); } // 基金标签 $tag = ""; if (!empty($param['tag']) && is_string($param['tag'])) { $tag = $param['tag']; } // 认购结束时间要大于 认购开始时间 if (strtotime($param['end_time']) <= strtotime($param['start_time'])) { return $this->toData('1', ' 认购结束时间 晚于 认购开始时间'); } // 1.0 判断基金号是否已经存在 $preStock = PreFundStockModel::where('stock_code', $param['stock_code'])->find(); if (!empty($preStock)) { return $this->toData('1', '基金号已经存在'); } // 历史走势 起始日期 if (empty($param['start_date']) || !is_string($param['start_date'])) { return $this->toData('1', '历史走势 起始日期 无效'); } // 历史走势 结束日期 if (empty($param['end_date']) || !is_string($param['end_date'])) { return $this->toData('1', '历史走势 结束日期 无效'); } if (strtotime($param['end_date']) <= strtotime($param['start_date']) || strtotime($param['end_date']) - time() > 0) { return $this->toData('1', '历史走势-开始日期 要大于 历史走势-结束日期 ; 历史走势-结束日期 要小于 当前时间'); } // 历史走势 起始值 if (empty($param['start_point']) || !is_numeric($param['start_point'])) { return $this->toData('1', '历史走势 起始值 无效'); } // 历史走势 结束值 if (empty($param['end_point']) || !is_numeric($param['end_point'])) { return $this->toData('1', '历史走势 结束值 无效'); } Db::startTrans(); // 新增数据 $preFundStock = new PreFundStockModel(); $preFundStock->stock_code = $param['stock_code']; $preFundStock->stock_name = $param['stock_name']; $preFundStock->stock_type = $param['stock_type']; $preFundStock->show_interest = $param['show_interest'] ?? 66; $preFundStock->tape = $param['tape'] ?? 1; $preFundStock->status = $param['status'] ?? 0; $preFundStock->min_price = $param['min_price']; $preFundStock->rate = $param['rate']; $preFundStock->cycle = $param['cycle']; $preFundStock->start_time = $param['start_time']; $preFundStock->end_time = $param['end_time']; $preFundStock->sort = $param['sort'] ?? 0; $preFundStock->interest_type = $param['interest_type']; $preFundStock->cycle_type = $param['cycle_type']; $preFundStock->phase_count = $param['phase_count'] ?? 1; $preFundStock->is_delete = PreFundStockModel::IS_DELETE_NO; $preFundStock->open_status = PreFundStockModel::OPEN_STATUS_NO; $preFundStock->create_time = date('Y-m-d H:i:s'); $preFundStock->update_time = date('Y-m-d H:i:s'); $preFundStock->stock_info = $param['stock_info'] ?? ""; $preFundStock->logo = $param['logo']; $preFundStock->tag = $tag; $preFundStock->remark = $param['remark']; $preFundStock->product_file = json_encode($param['product_file']); $preFundStock->current_manager = json_encode($param['current_manager']); $preFundStockBool = $preFundStock->save(); if (!$preFundStockBool) { Db::rollback(); return $this->toData('1', '新增基金失败'); } // 基金历史走势 $HistoryStock = new HistoryFundStockModel(); $HistoryStock->stock_code = $param['stock_code']; $HistoryStock->start_date = $param['start_date']; $HistoryStock->end_date = $param['end_date']; $HistoryStock->start_point = $param['start_point']; $HistoryStock->end_point = $param['end_point']; $HistoryStock->history_info = $this->autoHistory($param['start_date'], $param['end_date'], $param['start_point'], $param['end_point']); $HistoryStockBool = $HistoryStock->save(); if (!$HistoryStockBool) { Db::rollback(); return $this->toData('1', '新增基金走势失败'); } Db::commit(); return $this->toData('0', 'SUCCESS'); } catch (\Exception $exception) { Db::rollback(); return $this->toData('1', '系统繁忙', [$exception->getMessage()]); } } // 编辑 public function edit($param) { try { if (empty($param['id']) || !is_numeric($param['id'])) { return $this->toData('1', '主键 无效'); } $preFundStock = PreFundStockModel::where('id', $param['id'])->where('is_delete', PreFundStockModel::IS_DELETE_NO)->find(); if (empty($preFundStock)) { return $this->toData('1', '主键 无效'); } // 已中签或者已上市不支持修改 // if ($preFundStock->open_status == PreFundStockModel::OPEN_STATUS_HAD) { // return $this->toData('1', '已上市 不支持修改'); // } // 基金类型 if (empty($param['stock_type']) || !in_array($param['stock_type'], array_keys(PreFundStockModel::$stockTypeList))) { return $this->toData('1', '基金类型 无效'); } if ($preFundStock->had_get_price == 0) { // 基金代码 if (empty($param['stock_code']) || !is_string($param['stock_code'])) { return $this->toData('1', '基金代码 无效'); } // 基金名称 if (empty($param['stock_name']) || !is_string($param['stock_name'])) { return $this->toData('1', '基金代码 无效'); } // 单股价格 if (empty($param['min_price']) || !is_numeric($param['min_price']) || $param['min_price'] <= 0) { return $this->toData('1', '最低申购金额 无效'); } // 开始认购时间 if (empty($param['start_time']) || !is_string($param['start_time'])) { return $this->toData('1', '开始认购时间 无效'); } // 收益率 两位小数 if (empty($param['rate']) || !is_numeric($param['rate']) || $param['rate'] <= 0) { return $this->toData('1', '基金收益率 无效'); } // 基金周期 if (empty($param['cycle']) || !is_numeric($param['cycle']) || $param['cycle'] <= 0) { return $this->toData('1', '基金周期 无效'); } // 返利类型 if (empty($param['interest_type']) || !in_array($param['interest_type'], array_keys(PreFundStockModel::$interestTypeList))) { return $this->toData('1', '返利类型 无效'); } // 周期单位 if (empty($param['cycle_type']) || !in_array($param['cycle_type'], array_keys(PreFundStockModel::$cycleTypeList))) { return $this->toData('1', '返利类型 无效'); } } // 认购结束时间 if (empty($param['end_time']) || !is_string($param['end_time'])) { return $this->toData('1', '认购结束时间 无效'); } // 基金logo if (empty($param['logo']) || !is_string($param['logo'])) { return $this->toData('1', '基金logo 无效'); } // 基金标签 $tag = ""; if (!empty($param['tag']) && is_string($param['tag'])) { $tag = $param['tag']; } // 历史走势 起始日期 if (empty($param['start_date']) || !is_string($param['start_date'])) { return $this->toData('1', '历史走势 起始日期 无效'); } // 历史走势 结束日期 if (empty($param['end_date']) || !is_string($param['end_date'])) { return $this->toData('1', '历史走势 结束日期 无效'); } // 历史走势 起始值 if (empty($param['start_point']) || !is_numeric($param['start_point'])) { return $this->toData('1', '历史走势 起始值 无效'); } // 历史走势 结束值 if (empty($param['end_point']) || !is_numeric($param['end_point'])) { return $this->toData('1', '历史走势 结束值 无效'); } // 上市时间 要大于 认购结束时间 认购结束时间要大于 认购开始时间 if (strtotime($param['end_time']) <= strtotime($param['start_time'])) { return $this->toData('1', '认购结束时间 要晚于 认购开始时间'); } // 1.0 判断基金号是否已经存在 $preStock = PreFundStockModel::where('stock_code', $param['stock_code']) ->where('id', '<>', $param['id']) ->where('is_delete', PreFundStockModel::IS_DELETE_NO)->find(); if (!empty($preStock)) { return $this->toData('1', '基金号已经存在'); } Db::startTrans(); // 编辑数据 if ($preFundStock->had_get_price == 0) { $UpdatePreFundStockArr['stock_code'] = $param['stock_code']; $UpdatePreFundStockArr['stock_name'] = $param['stock_name']; $UpdatePreFundStockArr['status'] = $param['status'] ?? 0; $UpdatePreFundStockArr['min_price'] = $param['min_price']; $UpdatePreFundStockArr['start_time'] = $param['start_time']; $UpdatePreFundStockArr['rate'] = $param['rate']; $UpdatePreFundStockArr['cycle'] = $param['cycle']; $UpdatePreFundStockArr['interest_type'] = $param['interest_type']; $UpdatePreFundStockArr['cycle_type'] = $param['cycle_type']; $UpdatePreFundStockArr['phase_count'] = $param['phase_count'] ?? 1; $UpdatePreFundStockArr['tape'] = $param['tape'] ?? 1; } $UpdatePreFundStockArr['show_interest'] = $param['show_interest'] ?? 66; $UpdatePreFundStockArr['end_time'] = $param['end_time']; $UpdatePreFundStockArr['is_delete'] = PreFundStockModel::IS_DELETE_NO; $UpdatePreFundStockArr['update_time'] = date('Y-m-d H:i:s'); $UpdatePreFundStockArr['sort'] = $param['sort'] ?? 0; $UpdatePreFundStockArr['stock_info'] = $param['stock_info'] ?? ""; $UpdatePreFundStockArr['logo'] = $param['logo']; $UpdatePreFundStockArr['tag'] = $tag; $UpdatePreFundStockArr['remark'] = $param['remark']; $UpdatePreFundStockArr['product_file'] = json_encode($param['product_file']); $UpdatePreFundStockArr['current_manager'] = json_encode($param['current_manager']); $UpdatePreFundStockBool = PreFundStockModel::where('id', $param['id'])->update($UpdatePreFundStockArr); if (!$UpdatePreFundStockBool) { Db::rollback(); return $this->toData('1', '编辑基金失败'); } // 基金历史走势 $HistoryStockArr['stock_code'] = $param['stock_code']; $HistoryStockArr['start_date'] = $param['start_date']; $HistoryStockArr['end_date'] = $param['end_date']; $HistoryStockArr['start_point'] = $param['start_point']; $HistoryStockArr['end_point'] = $param['end_point']; $HistoryStockArr['history_info'] = $this->autoHistory($param['start_date'], $param['end_date'], $param['start_point'], $param['end_point']); $HistoryStock = HistoryFundStockModel::where('stock_code', $param['stock_code'])->find(); if (empty($HistoryStock)) { HistoryFundStockModel::where('stock_code', $preFundStock->stock_code)->delete(); $HistoryStockBool = HistoryFundStockModel::create($HistoryStockArr); } else { $HistoryStockBool = HistoryFundStockModel::where('stock_code', $param['stock_code'])->update($HistoryStockArr); } if (!$HistoryStockBool) { Db::rollback(); return $this->toData('1', '编辑基金走势失败'); } Db::commit(); return $this->toData('0', 'SUCCESS'); } catch (\Exception $exception) { Db::rollback(); return $this->toData('1', '系统繁忙', [$exception->getMessage()]); } } // 上市 public function open($param) { try { if (empty($param['id']) || !is_numeric($param['id'])) { return $this->toData('1', '主键 无效'); } // $isReal = 1; // if (isset($param['is_real']) && is_numeric($param['is_real']) && $param['is_real'] == '2') { // $isReal = 2; // } $preFundStock = PreFundStockModel::where('id', $param['id'])->where('is_delete', PreFundStockModel::IS_DELETE_NO)->find(); if (empty($preFundStock)) { return $this->toData('1', '主键 无效'); } // 判断是否签名 // if ($preFundStock->sign_status != PreFundStockModel::SIGN_STATUS_DONE) { // return $this->toData('1', '还未签名'); // } // if ($preFundStock->open_status != PreFundStockModel::OPEN_STATUS_NO) { // return $this->toData('1', '无法操作'); // } // 修改基金状态 $num = PreFundStockModel::where('id', $preFundStock->id)->update(['open_status' => PreFundStockModel::OPEN_STATUS_HAD, 'open_time' => date('Y-m-d H:i:s'), 'update_time' => date('Y-m-d H:i:s')]); if ($num <= 0) { return $this->toData('1', '基金状态修改失败-上市'); } return $this->toData('0', 'SUCCESS'); } catch (\Exception $exception) { Log::error("基金上市失败 " . $exception->getMessage()); return $this->toData('1', '系统繁忙', [$exception->getMessage()]); } } // 退市 public function close($param) { try { if (empty($param['id']) || !is_numeric($param['id'])) { return $this->toData('1', '主键 无效'); } $preFundStock = PreFundStockModel::where('id', $param['id'])->where('is_delete', PreFundStockModel::IS_DELETE_NO)->find(); if (empty($preFundStock)) { return $this->toData('1', '主键 无效'); } // if ($preFundStock->open_status != PreFundStockModel::OPEN_STATUS_HAD) { return $this->toData('1', '上市中 无法操作'); } // 修改基金状态 $num = PreFundStockModel::where('id', $preFundStock->id)->update(['open_status' => PreFundStockModel::OPEN_STATUS_OUT, 'close_time' => date('Y-m-d H:i:s'), 'update_time' => date('Y-m-d H:i:s')]); if ($num <= 0) { return $this->toData('1', '基金状态修改失败-退市'); } return $this->toData('0', 'SUCCESS'); } catch (\Exception $exception) { Log::error("基金退市失败 " . $exception->getMessage()); return $this->toData('1', '系统繁忙', [$exception->getMessage()]); } } // 删除 public function del($param) { try { if (empty($param['id']) || !is_numeric($param['id'])) { return $this->toData('1', '主键 无效'); } $preFundStock = PreFundStockModel::where('id', $param['id'])->where('is_delete', PreFundStockModel::IS_DELETE_NO)->find(); if (empty($preFundStock)) { return $this->toData('1', '主键 无效'); } // if ($preFundStock->open_status != PreFundStockModel::OPEN_STATUS_HAD) { return $this->toData('1', '上市中 无法操作'); } // 修改删除状态 $num = PreFundStockModel::where('id', $preFundStock->id)->update([ 'is_delete' => PreFundStockModel::IS_DELETE_YES, 'update_time' => date('Y-m-d H:i:s')]); if ($num <= 0) { return $this->toData('1', '基金删除失败'); } return $this->toData('0', 'SUCCESS'); } catch (\Exception $exception) { Log::error("基金删除失败 " . $exception->getMessage()); return $this->toData('1', '系统繁忙', [$exception->getMessage()]); } } private function autoHistory($startDate, $endDate, $startPoint, $endPoint) { $startDateOjb = new DateTime($startDate); $endDateOjb = new DateTime($endDate); $endDateOjb->modify('+1 day'); //DateTime 取两个日期中间日期,不含结束日期 $period = new DatePeriod($startDateOjb, new DateInterval('P1D'), $endDateOjb); $interval = $startDateOjb->diff($endDateOjb); $daysCount = $interval->format('%a'); $numberArr = $this->autoNumber($startPoint, $endPoint, $daysCount); $start = 0; foreach ($period as $k => $date) { $dates[$date->format("Y-m-d")] = number_format($start += $numberArr[$k], 2, '.', ''); } return json_encode($dates); } private function autoNumber($startPoint, $endPoint, $count) { $rand = round(($endPoint - $startPoint) / $count, 2); $randomNumbers = array(); $randomNumbers[] = $startPoint; for ($i = 0; $i < $count - 2; $i++) { $temp = bcmul(rand(1, 10) > 4 ? 1 : -1, (rand(1, 10) > 5 ? rand(1, 5) : rand(4, 8)) / 100, 2); // 生成随机的增减值 $randomChange = bcmul(rand(1, 10) > 4 ? 1 : -1, rand(1, 10) > 5 ? rand(1, 10) > 3 ? $rand * 2 : $rand * 4 : $rand * 3, 2); $randomChange = bcadd($randomChange, $temp, 2); // 将当前值添加到数组中 $randomNumbers[] = round($randomChange, 2); } $end = round($endPoint - array_sum($randomNumbers), 2); if (abs($end) > 30) { return $this->autoNumber($startPoint, $endPoint, $count); } else { $randomNumbers[] = $end; return $randomNumbers; } } public function interest() { try { // $interestSwitch = env(); // if (!$interestSwitch)return; $today = date("Y-m-d"); $interestList = UserStockFundInterestReceiptModel::where("return_date", $today)->where('status', UserStockFundInterestReceiptModel::STATUS_ONE)->select(); if (count($interestList) == 0) { trace('fund_interest count=0 基金没有需要处理的返息单-完成', 'error'); return json(["SUCCESS"]); } foreach ($interestList as $interestV) { try { // 单个股票 开始事务 Db::startTrans(); $vId = $interestV->id; //用户基金账户加钱 $beforeAmount = UserStockFundModel::where('stock_id', 'USD')->where('user_id', $interestV->user_id)->value('usable_num'); if (empty($beforeAmount)) { Db::rollback(); trace("基金返息失败0 返息单ID=$vId", 'error'); return json(["基金返息失败0"]); } $addNum = bcadd($interestV->capital, $interestV->interest, 18);//本金+利息 $addBool = UserStockFundModel::where('user_id', $interestV->user_id)->where('stock_id', 'USD')->inc('usable_num', $addNum)->update(['update_time' => date('Y-m-d H:i:s')]); if (!$addBool) { Db::rollback(); trace("基金返息失败1 返息单ID=$vId", 'error'); return json(["基金返息失败1"]); } // 新增用户基金账户流水 // 生成流水 $userStockLog = new UserStockFundLogModel(); $userStockLog->user_id = $interestV->user_id; $userStockLog->change_type = 19; $userStockLog->stock_id = 'USD'; $userStockLog->before_num = $beforeAmount; $userStockLog->change_num = $addNum; $userStockLog->order_id = $interestV->order_no; $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(); trace("基金返息失败2 返息单ID=$vId", 'error'); return json(["基金返息失败2"]); } //修改返息单状态 $interestReceiptUpdateBool = UserStockFundInterestReceiptModel::where('id', $interestV->id)->update(['status' => UserStockFundInterestReceiptModel::STATUS_TWO, 'update_time' => date('Y-m-d H:i:s')]); if (!$interestReceiptUpdateBool) { Db::rollback(); trace("基金返息失败3 返息单ID=$vId", 'error'); return json(["基金返息失败3"]); } //修改订单状态 $order = UserFundPreStockOrderModel::where('id', $interestV->order_id)->find(); if (empty($order)) { Db::rollback(); trace("基金返息失败4 返息单ID=$vId", 'error'); return json(["基金返息失败4"]); } if ($order->phase_count == $interestV->phase_time) { $orderStatus = UserFundPreStockOrderModel::STATUS_THREE;//已结束 } else { $orderStatus = UserFundPreStockOrderModel::STATUS_TWO;//进行中 } $order->status = $orderStatus; $order->save(); // 提交事务 Db::commit(); } catch (\Exception $exception) { Db::rollback(); trace("基金返息息失败5-exception " . $exception->getMessage(), 'error'); return json(["基金返息失败5-exception"]); } } trace('基金返息-完成', 'error'); return json(["SUCCESS"]); } catch (\Exception $exception) { trace("基金返息失败6-exception " . $exception->getMessage(), 'error'); return json([$exception->getMessage()]); } } public function referStockAdd($param) { try { $bool = PreFundStockReferModel::insert(['name' => $param['name'], 'year' => $param['year'], 'rate' => $param['rate']]); if (!$bool) { return $this->toData('1', '基金状态修改失败-退市'); } return $this->toData('0', 'SUCCESS'); } catch (\Exception $exception) { return $this->toData('1', '系统繁忙', [$exception->getMessage()]); } } public function referStockDel($param) { try { $bool = PreFundStockReferModel::where('id', $param['id'])->delete(); if (!$bool) { return $this->toData('1', '基金状态修改失败-退市'); } return $this->toData('0', 'SUCCESS'); } catch (\Exception $exception) { return $this->toData('1', '系统繁忙', [$exception->getMessage()]); } } }