info('RUN Command BusinessStoreOptimized on Day: ' . $executeDay); $this->info('RUN Command BusinessStoreOptimized present Day: ' . $presentDay); \Log::channel('cron')->info('RUN Command BusinessStoreOptimized on Day: ' . $executeDay); \Log::channel('cron')->info('RUN Command BusinessStoreOptimized present Day: ' . $presentDay); $this->logMemoryUsage('Command Start'); if ($executeDay !== $presentDay) { $this->info('NOT RUN Command BusinessStoreOptimized is not present Day: ' . $presentDay); \Log::channel('cron')->info('NOT RUN Command BusinessStoreOptimized is not present Day: ' . $presentDay); return 0; } $this->timeStart = microtime(true); // Argumente mit Standardwerten für den Vormonat $this->month = $this->argument('month') ?: (int) date("m", strtotime("-1 month")); $this->year = $this->argument('year') ?: (int) date("Y", strtotime("-1 month")); $this->info('RUN Command BusinessStoreOptimized on month: ' . $this->month . ' | year: ' . $this->year); $this->logMemoryUsage('Parameters initialized'); // Prüfe --clear Option und lösche gespeicherte Daten falls gewünscht if ($this->option('clear')) { $this->executeWithErrorHandling('Clear Stored Data', function () { $this->clearStoredData(); }); } // Prozesse ausführen mit optimierter Fehlerbehandlung $this->executeWithErrorHandling('Business Structure Storage', function () { \Log::channel('cron')->info('RUN Command BusinessStoreOptimized Business Structure Storage'); $this->storeBusinessStructureUsersDetailMonth(); }); $this->executeWithErrorHandling('Commission Calculation', function () { \Log::channel('cron')->info('RUN Command BusinessStoreOptimized Commission Calculation'); $this->userBusinessCommissionsToCredit(); }); // Auskommentierte Prozesse bleiben inaktiv // $this->userCreatePaymentCreditsPDF(); // $this->userLevelUpdate(); // $this->storeBusinessStructureUsersDetailPeriod(1, 6); $this->logExecutionTime('COMMAND COMPLETED SUCCESSFULLY'); $this->logMemoryUsage('Command End'); \Log::channel('cron')->info('COMMAND COMPLETED SUCCESSFULLY'); return 0; } catch (\Exception $e) { $this->error('Command failed with error: ' . $e->getMessage()); $this->error('Stack trace: ' . $e->getTraceAsString()); $this->logExecutionTime('COMMAND FAILED'); \Log::channel('cron')->info('COMMAND FAILED'); return 1; } } private function storeBusinessStructureUsersDetailMonth() { $this->info('storeBusinessStructureUsersDetailMonth month: ' . $this->month . ' year:' . $this->year); try { $businessUsersStore = new BusinessUsersStoreOptimized($this->month, $this->year); $businessUsersStore->storeUserBusinessStructure(); $businessUsersStore->storeBusinessUsersDetail(); $bool = $businessUsersStore->storeBusinessCompleted(); $this->logExecutionTime('END Command storeBusinessStructureUsersDetailMonth: ' . $bool); } catch (\Exception $e) { $this->error('Error in storeBusinessStructureUsersDetailMonth: ' . $e->getMessage()); throw $e; } } private function userBusinessCommissionsToCredit() { $this->info('userBusinessCommissionsToCredit month: ' . $this->month . ' year:' . $this->year); try { $userPaymentCredits = new UserPaymentCredits($this->month, $this->year); $userBusinesses = $userPaymentCredits->getUserBusinessByMonthYear(); $processedCount = 0; foreach ($userBusinesses as $userBusiness) { $ret = $userPaymentCredits->addUserCreditItem($userBusiness); $this->info('userBusinessCredit: ' . $ret->user_id . ' : Team: ' . $ret->commission_pp_total . ' | Shop: ' . $ret->commission_shop_sales); $processedCount++; // Memory-Check alle 100 User if ($processedCount % 100 === 0) { $this->logMemoryUsage("After processing {$processedCount} users"); } } $this->info("Processed {$processedCount} user businesses total"); $this->logExecutionTime('END Command userBusinessCommissionsToCredit:'); } catch (\Exception $e) { $this->error('Error in userBusinessCommissionsToCredit: ' . $e->getMessage()); throw $e; } } private function userCreatePaymentCreditsPDF() { $this->info('userCreatePaymentCreditsPDF month: ' . $this->month . ' year:' . $this->year); try { $userPaymentCredits = new UserPaymentCredits($this->month, $this->year); $creditItemUsers = $userPaymentCredits->getUserCreditItemUsersByMonthYear(); $processedCount = 0; foreach ($creditItemUsers as $creditItemUser) { $bool = $userPaymentCredits->makeCreditPaymentPDF($creditItemUser->user_id, $this->sendCreditMail); $this->info('creditsPDF: ' . $bool . ' user_id: ' . $creditItemUser->user_id); $processedCount++; // Memory-Check alle 50 PDFs if ($processedCount % 50 === 0) { $this->logMemoryUsage("After processing {$processedCount} PDFs"); } } $this->info("Created {$processedCount} PDF files total"); $this->logExecutionTime('END Command userCreatePaymentCreditsPDF:'); } catch (\Exception $e) { $this->error('Error in userCreatePaymentCreditsPDF: ' . $e->getMessage()); throw $e; } } private function userLevelUpdate() { $this->info('userLevelUpdate month: ' . $this->month . ' year:' . $this->year); try { $userLevelUpdate = new UserLevelUpdate($this->month, $this->year); $levelUpdateUsers = $userLevelUpdate->getUserBusinessByMonthYear(); $updatedCount = 0; foreach ($levelUpdateUsers as $userBusiness) { $ret = $userLevelUpdate->makeUserLevelUpdate($userBusiness, $this->sendUpdateMail); if ($ret) { $this->info('updateLevel: ' . $userBusiness->user->id . ' | ' . $userBusiness->user->email . ' | ' . 'from: ' . $userBusiness->m_level_id . ' ' . $userBusiness->user_level_name . ' | ' . 'to: ' . $ret); $updatedCount++; } } $this->info("Updated {$updatedCount} user levels total"); $this->logExecutionTime('END Command userLevelUpdate:'); } catch (\Exception $e) { $this->error('Error in userLevelUpdate: ' . $e->getMessage()); throw $e; } } private function storeBusinessStructureUsersDetailPeriod($from, $to) { try { for ($i = $from; $i <= $to; $i++) { $this->info('Store Business Structure Users Detail month: ' . $i . ' year:' . $this->year); $this->logMemoryUsage("Before month {$i}"); $businessUsersStore = new BusinessUsersStoreOptimized($i, $this->year); $businessUsersStore->storeUserBusinessStructure(); $businessUsersStore->storeBusinessUsersDetail(); $bool = $businessUsersStore->storeBusinessCompleted(); $this->logExecutionTime('Period BusinessStore: ' . $bool); $this->logMemoryUsage("After month {$i}"); } } catch (\Exception $e) { $this->error('Error in storeBusinessStructureUsersDetailPeriod: ' . $e->getMessage()); throw $e; } } /** * Löscht gespeicherte Business Structure Daten für den angegebenen Monat/Jahr */ private function clearStoredData() { try { $this->info("Clearing stored business data for month: {$this->month} | year: {$this->year}"); // Finde bestehende UserBusinessStructure $existingStructure = UserBusinessStructure::where('year', $this->year) ->where('month', $this->month) ->first(); if (!$existingStructure) { $this->info('No stored business structure found to clear'); return; } $structureId = $existingStructure->id; $this->info("Found existing structure with ID: {$structureId}"); // Lösche zugehörige UserBusiness Einträge $deletedUserBusinesses = UserBusiness::where('b_structure_id', $structureId)->count(); if ($deletedUserBusinesses > 0) { UserBusiness::where('b_structure_id', $structureId)->delete(); $this->info("Deleted {$deletedUserBusinesses} UserBusiness records"); } // Lösche die UserBusinessStructure $existingStructure->delete(); $this->info("Deleted UserBusinessStructure with ID: {$structureId}"); // Garbage Collection nach dem Löschen gc_collect_cycles(); $this->info('Successfully cleared all stored business data'); $this->logMemoryUsage('After clearing data'); } catch (\Exception $e) { $this->error('Error clearing stored data: ' . $e->getMessage()); throw $e; } } private function logExecutionTime($message) { $diff = microtime(true) - $this->timeStart; $sec = intval($diff); $micro = $diff - $sec; $this->info($message . ' | Time: ' . $sec . 'sec :' . round($micro * 1000, 4) . " ms"); } /** * Führt eine Funktion mit Fehlerbehandlung aus */ private function executeWithErrorHandling(string $processName, callable $callback): void { try { $startTime = microtime(true); $this->info("Starting: {$processName}"); $this->logMemoryUsage("Before {$processName}"); $callback(); $endTime = microtime(true); $duration = round(($endTime - $startTime) * 1000, 2); $this->info("Completed: {$processName} in {$duration}ms"); $this->logMemoryUsage("After {$processName}"); } catch (\Exception $e) { $this->error("Error in {$processName}: " . $e->getMessage()); $this->error("Stack trace: " . $e->getTraceAsString()); throw $e; } } /** * Loggt aktuelle Memory-Nutzung */ private function logMemoryUsage(string $checkpoint): void { $currentMemory = memory_get_usage(); $peakMemory = memory_get_peak_usage(); $memoryLimit = $this->parseMemoryLimit(ini_get('memory_limit')); $currentFormatted = $this->formatBytes($currentMemory); $peakFormatted = $this->formatBytes($peakMemory); $limitFormatted = $this->formatBytes($memoryLimit); $usagePercent = round(($currentMemory / $memoryLimit) * 100, 2); $this->info("[{$checkpoint}] Memory: {$currentFormatted} / {$limitFormatted} ({$usagePercent}%) | Peak: {$peakFormatted}"); if ($usagePercent > 80) { $this->warn("High memory usage detected at {$checkpoint}: {$usagePercent}%"); } } /** * Konvertiert Memory-Limit String zu Bytes */ private function parseMemoryLimit(string $limit): int { $limit = trim($limit); $last = strtolower($limit[strlen($limit) - 1]); $number = (int) $limit; switch ($last) { case 'g': $number *= 1024; case 'm': $number *= 1024; case 'k': $number *= 1024; } return $number; } /** * Formatiert Bytes in lesbare Einheiten */ private function formatBytes(int $bytes, int $precision = 2): string { $units = array('B', 'KB', 'MB', 'GB', 'TB'); for ($i = 0; $bytes > 1024 && $i < count($units) - 1; $i++) { $bytes /= 1024; } return round($bytes, $precision) . ' ' . $units[$i]; } }