You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
353 lines
16 KiB
353 lines
16 KiB
<?php
|
|
|
|
namespace app\home\service;
|
|
|
|
use app\model\FeeSettingModel;
|
|
use app\model\HistoryFundStockModel;
|
|
use app\model\PreFundStockModel;
|
|
use app\model\PreFundStockReferModel;
|
|
use app\model\StockMarketModel;
|
|
use app\model\UserFundPreStockOrderModel;
|
|
use app\model\UserStockFundInterestReceiptModel;
|
|
use app\model\UserModel;
|
|
use app\model\UserStockFundLogModel;
|
|
use app\model\UserStockFundModel;
|
|
use DatePeriod;
|
|
use DateTime;
|
|
use DateInterval;
|
|
use think\facade\Db;
|
|
|
|
|
|
class FundService extends BaseHomeService
|
|
{
|
|
|
|
// 基金列表
|
|
public function index(array $param): array
|
|
{
|
|
try {
|
|
if (empty($param['page']) || !is_numeric($param['page']) || empty($param['limit']) || !is_numeric($param['limit'])) {
|
|
$param['page'] = 1;
|
|
$param['limit'] = 10;
|
|
}
|
|
|
|
$openStatusOrder = [2, 1, 3]; // 指定的用户ID顺序
|
|
// 构建排序字符串
|
|
$orderString = 'FIELD(open_status, ' . implode(',', $openStatusOrder) . ')';
|
|
|
|
$where = [];
|
|
// $where[] = ['open_status', '=', PreFundStockModel::OPEN_STATUS_HAD];
|
|
$where[] = ['is_delete', '=', PreFundStockModel::IS_DELETE_NO];
|
|
$rows = PreFundStockModel::where($where)->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()]);
|
|
}
|
|
}
|
|
}
|