File Manager

Path: /home/liffinac1/domains/impactxtmtrading.com/private_html/app/Jobs/

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());
        }
    }
}