|
|
<?php
|
|
|
|
|
|
namespace App\Services;
|
|
|
|
|
|
use Carbon\Carbon;
|
|
|
use DateTime;
|
|
|
use Illuminate\Support\Facades\DB;
|
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
|
|
class DayCutService
|
|
|
{
|
|
|
public static function Cut($day){
|
|
|
if(empty($day)){
|
|
|
return ['status'=>false,'msg'=>'请输入日切日期'];
|
|
|
}
|
|
|
if($day>date('Y-m-d')){
|
|
|
return ['status'=>false,'msg'=>'不可提前日切'];
|
|
|
}
|
|
|
|
|
|
$Carbon_day = Carbon::parse($day);
|
|
|
|
|
|
|
|
|
$members = DB::table("members")->where("is_del", 0)->get();
|
|
|
$configs = DB::table("configs")->get();
|
|
|
$config_wait_day=null;//计息等待天数
|
|
|
$cunkuan_rate=null;//存款利率
|
|
|
$start_time=null;//日切开始时间
|
|
|
foreach($configs as $config){
|
|
|
if($config->label == "计息等待"){
|
|
|
$config_wait_day = $config->value;
|
|
|
}
|
|
|
if($config->label == "存款利率"){
|
|
|
$cunkuan_nian_rate = bcdiv($config->value, '100', 10);//年化利率
|
|
|
$cunkuan_rate = bcdiv($cunkuan_nian_rate, '365', 10);//日利率
|
|
|
}
|
|
|
if($config->label == "日切开始时间"){
|
|
|
$start_time =$config->value;
|
|
|
}
|
|
|
}
|
|
|
// 兼容全角冒号,并补全秒
|
|
|
$start_time = trim(str_replace(':', ':', $start_time));
|
|
|
if (substr_count($start_time, ':') === 1) {
|
|
|
$start_time .= ':00';
|
|
|
}
|
|
|
|
|
|
// 构造当天的日切时间点
|
|
|
$cutoff_datetime = $day . ' ' . $start_time;
|
|
|
|
|
|
// 比较当前时间是否已到日切时间
|
|
|
// dd($day);
|
|
|
if ($day == date('Y-m-d')) {
|
|
|
if (Carbon::now()->lt(Carbon::parse($cutoff_datetime))) {
|
|
|
return ['status' => false, 'msg' => '未到日切开始时间'];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if($config_wait_day === null){
|
|
|
return ['status'=>false,'msg'=>'请配置计息等待天数'];
|
|
|
}
|
|
|
if($cunkuan_rate === null){
|
|
|
return ['status'=>false,'msg'=>'请配置存款利率'];
|
|
|
}
|
|
|
$daysToAdd = $config_wait_day;
|
|
|
$successCount = 0;
|
|
|
$failures = [];
|
|
|
foreach($members as $member){
|
|
|
if (!empty($member->day_cut_at)) {
|
|
|
$member_cutday = Carbon::parse($member->day_cut_at)->startOfDay();
|
|
|
$target_day = $Carbon_day->copy()->startOfDay();
|
|
|
if ($member_cutday>=$target_day) {//只要用户已经日切过 >= 目标日期,就跳过
|
|
|
continue;
|
|
|
}
|
|
|
}
|
|
|
try{
|
|
|
DB::transaction(function () use ($member, $Carbon_day, $daysToAdd, $cunkuan_rate, $day) {
|
|
|
self::processMemberDayCut($member, $Carbon_day, $daysToAdd, $cunkuan_rate, $day);
|
|
|
}, 3); // 每个用户最多重试3次(应对死锁)
|
|
|
|
|
|
$successCount++;
|
|
|
}catch(\Exception $e) {
|
|
|
// 记录失败,但继续处理下一个用户
|
|
|
Log::error("日切失败 - 用户ID: {$member->id}, 错误: " . $e->getMessage(), [
|
|
|
'member_id' => $member->id,
|
|
|
'date' => $day,
|
|
|
'exception' => $e,
|
|
|
]);
|
|
|
$failures[] = [
|
|
|
'member_id' => $member->id,
|
|
|
'error' => $e->getMessage(),
|
|
|
];
|
|
|
}
|
|
|
|
|
|
}
|
|
|
DB::table('configs')->where('label', '日切日期')->update(['value' => $day]);
|
|
|
$msg = "日切完成:成功 {$successCount} 人";
|
|
|
if (!empty($failures)) {
|
|
|
$msg .= ",失败 " . count($failures) . " 人(详见日志)";
|
|
|
}
|
|
|
return ['status'=>true,'msg'=>$msg];
|
|
|
}
|
|
|
private static function processMemberDayCut($member, $Carbon_day, $daysToAdd, $cunkuan_rate, $day){
|
|
|
$transactions = DB::table("transactions")->where([ //查找未计算利息的交易
|
|
|
"member_id" => $member->id,
|
|
|
"is_del" => 0,
|
|
|
"status" => 3,
|
|
|
"is_interest_eligible" => 0
|
|
|
])->whereIn("type",[1,3])->orderBy("verify_time","asc")->get();
|
|
|
$member_interest_balance = (string)$member->interest_balance;//用户表计息本金余额
|
|
|
foreach($transactions as $transaction){
|
|
|
Log::info("处理交易 - 用户ID: {$member->id}, 交易ID: {$transaction->id}, 审核时间: {$transaction->verify_time}, 类型: {$transaction->type}");
|
|
|
$shenHeDate_n = Carbon::parse($transaction->verify_time)->startOfDay()->addDays($daysToAdd);
|
|
|
$trans_amount= (string)$transaction->amount; //本笔流水金额
|
|
|
|
|
|
if($transaction->type == 1){//充值
|
|
|
if ($shenHeDate_n->lte($Carbon_day->startOfDay())) { // 如果审核通过时间加上指定天数小于等于目标日期
|
|
|
$member_interest_balance = bcadd($trans_amount, $member_interest_balance, 2);//新的计息本金余额
|
|
|
// $up_member=DB::table("members")->where("id", $member->id)->update(["interest_balance" => $new_interest_balance]);//更新用户表计息本金余额
|
|
|
$up_trans=DB::table("transactions")->where("id", $transaction->id)->update(["is_interest_eligible" => 1]);//更新交易表为已更新计入利息本金
|
|
|
}
|
|
|
}
|
|
|
if($transaction->type == 3){//提现
|
|
|
if ($shenHeDate_n->lte($Carbon_day->startOfDay())) { // 如果审核通过时间加上指定天数小于等于目标日期
|
|
|
$member_interest_balance = bcsub($member_interest_balance, $trans_amount, 2);//新的计息本金余额
|
|
|
if (bccomp($member_interest_balance, '0', 2) < 0) {
|
|
|
throw new \DomainException("用户 {$member->id} 计息余额不足,当前: {$member_interest_balance}, 尝试扣除: {$trans_amount}");
|
|
|
}
|
|
|
// $up_member=DB::table("members")->where("id", $member->id)->update(["interest_balance" => $new_interest_balance]);//更新用户表计息本金余额
|
|
|
$up_trans=DB::table("transactions")->where("id", $transaction->id)->update(["is_interest_eligible" => 1]);//更新交易表为更新计入利息本金
|
|
|
}
|
|
|
}
|
|
|
Log::info("处理交易 - 用户ID: {$member->id}, 交易ID: {$transaction->id}, 新计息本金余额: {$member_interest_balance}");
|
|
|
}
|
|
|
//开始计息
|
|
|
// $member_new=DB::table("members")->where("id", $member->id)->first();
|
|
|
$day_interest = bcmul($member_interest_balance, $cunkuan_rate, 2);//新的利息
|
|
|
$new_all_interest_balance = bcadd($member_interest_balance, $day_interest, 2);//新的 计息本金 余额
|
|
|
$new_all_balance=bcadd($member->balance,$day_interest,2);//新的 余额
|
|
|
$total_interest=bcadd($member->total_interest,$day_interest,2);//新的 总利息
|
|
|
//插入利息日志表
|
|
|
$insert_interest_log=DB::table("daily_interest_logs")->insert([
|
|
|
"member_id" => $member->id,
|
|
|
"date" => $day,
|
|
|
"date_balance" =>$member_interest_balance,
|
|
|
"interest_rate" => $cunkuan_rate,
|
|
|
"interest_amount" => $day_interest,
|
|
|
"is_del" => 0,
|
|
|
"created_at" => date("Y-m-d H:i:s"),
|
|
|
]);
|
|
|
|
|
|
$up_member=DB::table("members")->where("id", $member->id)->update([
|
|
|
"balance"=>$new_all_balance,
|
|
|
"interest_balance" => $new_all_interest_balance,
|
|
|
"total_interest"=>$total_interest,
|
|
|
"day_cut_at"=>$day,
|
|
|
]);//更新用户表计息本金余额
|
|
|
}
|
|
|
}
|