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, ]);//更新用户表计息本金余额 } }