File Manager
Viewing File: ProcessPlanInvestmentReturns.php
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Models\Investment;
use App\Models\Plans;
use App\Models\User;
use App\Models\Settings;
use App\Models\Tp_Transaction;
use App\Models\Notification;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\DB;
use App\Mail\NewRoi;
use App\Mail\EndPlan;
use App\Mail\NewNotification;
class ProcessPlanInvestmentReturns implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $investment;
/**
* Create a new job instance.
*/
public function __construct(Investment $investment = null)
{
$this->investment = $investment;
}
/**
* Execute the job.
*/
public function handle(): void
{
try {
Log::info('Starting ProcessPlanInvestmentReturns job');
// Check if trade mode is enabled in settings
$settings = Settings::where('id', 1)->first();
if (!$settings || $settings->trade_mode !== 'on') {
Log::info('Plan investment returns processing skipped - trade mode is off');
return;
}
// If specific investment provided, process only that one
if ($this->investment) {
$this->processInvestment($this->investment, $settings);
return;
}
// Process all active investments
$activeInvestments = Investment::where('active', 'yes')
->with(['uplan', 'puser'])
->get();
Log::info('Processing ' . $activeInvestments->count() . ' active investments');
foreach ($activeInvestments as $investment) {
$this->processInvestment($investment, $settings);
}
Log::info('Plan investment returns processing completed');
} catch (\Exception $e) {
Log::error('Error in ProcessPlanInvestmentReturns job: ' . $e->getMessage());
throw $e;
}
}
/**
* Process individual investment for ROI calculations
*/
private function processInvestment(Investment $investment, Settings $settings): void
{
try {
$plan = $investment->uplan;
$user = $investment->puser;
if (!$plan || !$user) {
Log::warning('Investment ID ' . $investment->id . ' has missing plan or user relationship');
return;
}
$now = Carbon::now();
// Check if investment has expired
if ($now->greaterThan($investment->expire_date)) {
$this->expireInvestment($investment, $plan, $user, $settings);
return;
}
// Check if user's trade mode is off
if ($user->trade_mode !== 'on') {
return;
}
// Calculate next ROI drop time based on plan interval
$nextDrop = $this->calculateNextDropTime($investment, $plan);
// Check weekend trading
$isWeekend = $now->isWeekend();
if ($isWeekend && $settings->weekend_trade !== 'on') {
// Update last_growth without adding ROI on weekends if weekend trade is off
if ($now->greaterThanOrEqualTo($nextDrop)) {
$investment->update(['last_growth' => $nextDrop]);
}
return;
}
// Process ROI if it's time
if ($now->greaterThanOrEqualTo($nextDrop)) {
$this->processROI($investment, $plan, $user, $settings, $nextDrop);
}
} catch (\Exception $e) {
Log::error('Error processing investment ID ' . $investment->id . ': ' . $e->getMessage());
}
}
/**
* Calculate next ROI drop time based on plan increment interval
*/
private function calculateNextDropTime(Investment $investment, Plans $plan): Carbon
{
$lastGrowth = $investment->last_growth;
return match($plan->increment_interval) {
'Monthly' => $lastGrowth->addDays(30),
'Weekly' => $lastGrowth->addWeek(),
'Daily' => $lastGrowth->addDay(),
'Hourly' => $lastGrowth->addHour(),
'Every 30 Minutes' => $lastGrowth->addMinutes(30),
'Every 10 Minutes' => $lastGrowth->addMinutes(10),
default => $lastGrowth->addDay(), // Default to daily
};
}
/**
* Process ROI calculation and distribution
*/
private function processROI(Investment $investment, Plans $plan, User $user, Settings $settings, Carbon $nextDrop): void
{
try {
// Calculate ROI increment
if ($plan->increment_type === 'Percentage') {
$increment = ($investment->amount * $plan->increment_amount) / 100;
} else {
$increment = (float) $plan->increment_amount;
}
// Update user balances
$user->update([
'roi' => $user->roi + $increment,
'account_bal' => $user->account_bal + $increment,
]);
// Update investment record
$currentTime = Carbon::now();
DB::table('investments')
->where('id', $investment->id)
->update([
'last_growth' => $currentTime,
'profit_earned' => ($investment->profit_earned ?? 0) + $increment,
]);
// Create transaction record
Tp_Transaction::create([
'user' => $user->id,
'plan' => $plan->name,
'amount' => $increment,
'user_plan_id' => $investment->id,
'type' => 'ROI',
'status' => 'Processed',
]);
// Create in-app notification
$this->createUserNotification(
$user->id,
'ROI Earnings Received',
"You have received a return of {$settings->currency}{$increment} from your investment in {$plan->name}.",
'success',
$investment->id,
'Investment'
);
// Send email notification if enabled
if ($user->sendroiemail === 'Yes') {
try {
$date = Carbon::now()->toDateTimeString();
Mail::to($user->email)->send(new NewRoi($user, $plan->name, $increment, $date, 'New Return on Investment(ROI)'));
} catch (\Exception $e) {
Log::error('Failed to send ROI email to user ' . $user->email . ': ' . $e->getMessage());
}
}
Log::info("ROI processed for investment ID {$investment->id}: {$increment}");
} catch (\Exception $e) {
Log::error('Error processing ROI for investment ID ' . $investment->id . ': ' . $e->getMessage());
throw $e;
}
}
/**
* Expire an investment and handle capital return
*/
private function expireInvestment(Investment $investment, Plans $plan, User $user, Settings $settings): void
{
try {
// Return capital if enabled
if ($settings->return_capital) {
$user->update([
'account_bal' => $user->account_bal + $investment->amount,
]);
// Create capital return transaction
Tp_Transaction::create([
'user' => $user->id,
'plan' => $plan->name,
'amount' => $investment->amount,
'type' => 'Investment Capital',
'status' => 'Processed',
]);
}
// Update investment status
$investment->update(['active' => 'expired']);
// Create completion notification
$totalProfit = $investment->profit_earned ?? 0;
$this->createUserNotification(
$user->id,
'Investment Plan Completed',
"Your investment plan '{$plan->name}' has been completed. Total profit earned: {$settings->currency}{$totalProfit}" .
($settings->return_capital ? ". Capital of {$settings->currency}{$investment->amount} has been returned to your account." : ""),
'info',
$investment->id,
'Investment'
);
// Send completion email if enabled
if ($user->sendinvplanemail === "Yes") {
try {
$objDemo = new \stdClass();
$objDemo->receiver_email = $user->email;
$objDemo->receiver_plan = $plan->name;
$objDemo->received_amount = "{$settings->currency}{$investment->amount}";
$objDemo->sender = $settings->site_name;
$objDemo->receiver_name = $user->name;
$objDemo->date = Carbon::now();
$objDemo->subject = "Investment plan completed";
Mail::to($user->email)->send(new EndPlan($objDemo));
} catch (\Exception $e) {
Log::error('Failed to send investment completion email to user ' . $user->email . ': ' . $e->getMessage());
}
}
Log::info("Investment ID {$investment->id} expired and processed");
} catch (\Exception $e) {
Log::error('Error expiring investment ID ' . $investment->id . ': ' . $e->getMessage());
throw $e;
}
}
/**
* Create user notification
*/
private function createUserNotification($userId, $title, $message, $type = 'success', $sourceId = null, $sourceType = null): void
{
try {
Notification::create([
'user_id' => $userId,
'title' => $title,
'message' => $message,
'type' => $type,
'is_read' => false,
'source_id' => $sourceId,
'source_type' => $sourceType
]);
} catch (\Exception $e) {
Log::error('Failed to create user notification: ' . $e->getMessage());
}
}
}