20-02-2026
This commit is contained in:
parent
a8b395e20d
commit
a00c42e770
252 changed files with 28785 additions and 8907 deletions
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Setting;
|
||||
use Illuminate\Console\Command;
|
||||
use App\Cron\BusinessUsersStore;
|
||||
use App\Cron\UserLevelUpdate;
|
||||
use App\Cron\UserPaymentCredits;
|
||||
use App\Models\Setting;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class BusinessStore extends Command
|
||||
{
|
||||
|
|
@ -27,14 +27,15 @@ class BusinessStore extends Command
|
|||
protected $description = 'Create Business Structure and UserDetails with optimized performance';
|
||||
|
||||
private $timeStart;
|
||||
|
||||
private $month;
|
||||
|
||||
private $year;
|
||||
|
||||
private $sendCreditMail = false;
|
||||
|
||||
private $sendUpdateMail = false;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
|
|
@ -45,6 +46,58 @@ class BusinessStore extends Command
|
|||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prüft ob der Command heute ausgeführt werden soll
|
||||
*
|
||||
* WICHTIG: Diese Methode verhindert, dass der Command täglich läuft!
|
||||
* Der Command sollte nur am konfigurierten Tag des Monats laufen.
|
||||
*
|
||||
* @return bool True wenn Command ausgeführt werden soll, False sonst
|
||||
*/
|
||||
private function shouldExecuteToday(): bool
|
||||
{
|
||||
// Hole konfigurierten Ausführungstag (Standard: 1 = Monatserster)
|
||||
$executeDay = (int) Setting::getContentBySlug('day-exectute-business-structur');
|
||||
|
||||
// Fallback: Wenn Setting leer oder 0, verwende Tag 1
|
||||
if ($executeDay === 0) {
|
||||
$executeDay = 1;
|
||||
$this->warn('Setting "day-exectute-business-structur" ist leer oder 0. Verwende Standard: Tag 1');
|
||||
\Log::channel('cron')->warning('BusinessStore: Setting day-exectute-business-structur is empty, using default: 1');
|
||||
}
|
||||
|
||||
$presentDay = (int) date('d');
|
||||
|
||||
// Logging für Debugging
|
||||
$this->info("BusinessStore: Configured Day: {$executeDay}, Present Day: {$presentDay}");
|
||||
\Log::channel('cron')->info("BusinessStore: Configured Day: {$executeDay}, Present Day: {$presentDay}");
|
||||
|
||||
// Prüfe ob heute der konfigurierte Tag ist
|
||||
if ($executeDay !== $presentDay) {
|
||||
// Erlaubnis zum Überschreiben für Entwicklung/Testing
|
||||
// ENV-Variable BUSINESS_FORCE_EXECUTE=true überschreibt den Check
|
||||
if (env('BUSINESS_FORCE_EXECUTE', false) === true) {
|
||||
$this->warn('⚠️ BUSINESS_FORCE_EXECUTE ist aktiv - Command wird trotz falschem Tag ausgeführt!');
|
||||
$this->warn('⚠️ Dies sollte NUR auf Test-Servern verwendet werden!');
|
||||
\Log::channel('cron')->warning('BusinessStore: FORCED execution via BUSINESS_FORCE_EXECUTE');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Command sollte heute NICHT laufen
|
||||
$this->info("❌ Command wird NICHT ausgeführt - falscher Tag (erwartet: {$executeDay}, heute: {$presentDay})");
|
||||
\Log::channel('cron')->info("BusinessStore: NOT EXECUTED - wrong day (expected: {$executeDay}, today: {$presentDay})");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Command wird ausgeführt
|
||||
$this->info("✅ Command wird ausgeführt - korrekter Tag ({$presentDay})");
|
||||
\Log::channel('cron')->info("BusinessStore: EXECUTING - correct day ({$presentDay})");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
|
|
@ -53,29 +106,21 @@ class BusinessStore extends Command
|
|||
public function handle()
|
||||
{
|
||||
try {
|
||||
$executeDay = (int) Setting::getContentBySlug('day-exectute-business-structur');
|
||||
$presentDay = (int) date('d');
|
||||
|
||||
$this->info('RUN Command BusinessStore on Day: ' . $executeDay);
|
||||
$this->info('RUN Command BusinessStore present Day: ' . $presentDay);
|
||||
\Log::channel('cron')->info('RUN Command BusinessStore on Day: ' . $executeDay);
|
||||
\Log::channel('cron')->info('RUN Command BusinessStore present Day: ' . $presentDay);
|
||||
$this->logMemoryUsage('Command Start');
|
||||
|
||||
if ($executeDay !== $presentDay) {
|
||||
$this->info('NOT RUN Command BusinessStore is not present Day: ' . $presentDay);
|
||||
\Log::channel('cron')->info('NOT RUN Command BusinessStore is not present Day: ' . $presentDay);
|
||||
// Prüfe ob Command am richtigen Tag ausgeführt werden soll
|
||||
if (! $this->shouldExecuteToday()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$this->logMemoryUsage('Command Start');
|
||||
|
||||
$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->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 BusinessStore on month: ' . $this->month . ' | year: ' . $this->year);
|
||||
\Log::channel('cron')->info('RUN Command BusinessStore on month: ' . $this->month . ' | year: ' . $this->year);
|
||||
$this->info('RUN Command BusinessStore on month: '.$this->month.' | year: '.$this->year);
|
||||
\Log::channel('cron')->info('RUN Command BusinessStore on month: '.$this->month.' | year: '.$this->year);
|
||||
$this->logMemoryUsage('Parameters initialized');
|
||||
|
||||
// Prozesse ausführen mit Fehlerbehandlung
|
||||
|
|
@ -98,9 +143,10 @@ class BusinessStore extends Command
|
|||
|
||||
return 0;
|
||||
} catch (\Exception $e) {
|
||||
$this->error('Command failed with error: ' . $e->getMessage());
|
||||
$this->error('Stack trace: ' . $e->getTraceAsString());
|
||||
$this->error('Command failed with error: '.$e->getMessage());
|
||||
$this->error('Stack trace: '.$e->getTraceAsString());
|
||||
$this->logExecutionTime('COMMAND FAILED');
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -108,25 +154,25 @@ class BusinessStore extends Command
|
|||
private function storeBusinessStructureUsersDetailMonth()
|
||||
{
|
||||
|
||||
$this->info('storeBusinessStructureUsersDetailMonth month: ' . $this->month . ' year:' . $this->year);
|
||||
$this->info('storeBusinessStructureUsersDetailMonth month: '.$this->month.' year:'.$this->year);
|
||||
$businessUsersStore = new BusinessUsersStore($this->month, $this->year);
|
||||
$businessUsersStore->storeUserBusinessStructure();
|
||||
$businessUsersStore->storeBusinessUsersDetail();
|
||||
$bool = $businessUsersStore->storeBusinessCompleted();
|
||||
|
||||
$this->logExecutionTime('END Command storeBusinessStructureUsersDetailMonth: ' . $bool);
|
||||
$this->logExecutionTime('END Command storeBusinessStructureUsersDetailMonth: '.$bool);
|
||||
}
|
||||
|
||||
private function userBusinessCommissionsToCredit()
|
||||
{
|
||||
|
||||
$this->info('userBusinessCommissionsToCredit month: ' . $this->month . ' year:' . $this->year);
|
||||
$this->info('userBusinessCommissionsToCredit month: '.$this->month.' year:'.$this->year);
|
||||
$userPaymentCredits = new UserPaymentCredits($this->month, $this->year);
|
||||
$userBusinesses = $userPaymentCredits->getUserBusinessByMonthYear();
|
||||
|
||||
foreach ($userBusinesses as $userBusiness) {
|
||||
$ret = $userPaymentCredits->addUserCreditItem($userBusiness);
|
||||
$this->info('userBusinessCredit: ' . $ret->user_id . ' : Team: ' . $ret->commission_pp_total . ' | Shop: ' . $ret->commission_shop_sales);
|
||||
$this->info('userBusinessCredit: '.$ret->user_id.' : Team: '.$ret->commission_pp_total.' | Shop: '.$ret->commission_shop_sales);
|
||||
}
|
||||
$this->logExecutionTime('END Command userBusinessCommissionsToCredit:');
|
||||
}
|
||||
|
|
@ -134,13 +180,13 @@ class BusinessStore extends Command
|
|||
private function userCreatePaymentCreditsPDF()
|
||||
{
|
||||
|
||||
$this->info('userCreatePaymentCreditsPDF month: ' . $this->month . ' year:' . $this->year);
|
||||
$this->info('userCreatePaymentCreditsPDF month: '.$this->month.' year:'.$this->year);
|
||||
$userPaymentCredits = new UserPaymentCredits($this->month, $this->year);
|
||||
$creditItemUsers = $userPaymentCredits->getUserCreditItemUsersByMonthYear();
|
||||
|
||||
foreach ($creditItemUsers as $creditItemUser) {
|
||||
$bool = $userPaymentCredits->makeCreditPaymentPDF($creditItemUser->user_id, $this->sendCreditMail);
|
||||
$this->info('creditsPDF: ' . $bool . ' user_id: ' . $creditItemUser->user_id);
|
||||
$this->info('creditsPDF: '.$bool.' user_id: '.$creditItemUser->user_id);
|
||||
}
|
||||
|
||||
$this->logExecutionTime('END Command userCreatePaymentCreditsPDF:');
|
||||
|
|
@ -149,7 +195,7 @@ class BusinessStore extends Command
|
|||
private function userLevelUpdate()
|
||||
{
|
||||
|
||||
$this->info('userLevelUpdate month: ' . $this->month . ' year:' . $this->year);
|
||||
$this->info('userLevelUpdate month: '.$this->month.' year:'.$this->year);
|
||||
|
||||
$userLevelUpdate = new UserLevelUpdate($this->month, $this->year);
|
||||
$levelUpdateUsers = $userLevelUpdate->getUserBusinessByMonthYear();
|
||||
|
|
@ -157,26 +203,24 @@ class BusinessStore extends Command
|
|||
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);
|
||||
$this->info('updateLevel: '.$userBusiness->user->id.' | '.$userBusiness->user->email.' | '.
|
||||
'from: '.$userBusiness->m_level_id.' '.$userBusiness->user_level_name.' | '.
|
||||
'to: '.$ret);
|
||||
}
|
||||
}
|
||||
$this->logExecutionTime('END Command userLevelUpdate:');
|
||||
}
|
||||
|
||||
|
||||
|
||||
private function storeBusinessStructureUsersDetailPeriod($from, $to)
|
||||
{
|
||||
for ($i = $from; $i <= $to; $i++) {
|
||||
$this->info('Store Business Structure Users Detail month: ' . $i . ' year:' . $this->year);
|
||||
$this->info('Store Business Structure Users Detail month: '.$i.' year:'.$this->year);
|
||||
$businessUsersStore = new BusinessUsersStore($i, $this->year);
|
||||
$businessUsersStore->storeUserBusinessStructure();
|
||||
$businessUsersStore->storeBusinessUsersDetail();
|
||||
$bool = $businessUsersStore->storeBusinessCompleted();
|
||||
|
||||
$this->logExecutionTime('Period BusinessStore: ' . $bool);
|
||||
$this->logExecutionTime('Period BusinessStore: '.$bool);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -186,6 +230,6 @@ class BusinessStore extends Command
|
|||
$sec = intval($diff);
|
||||
$micro = $diff - $sec;
|
||||
|
||||
$this->info($message . ' | Time: ' . $sec . 'sec :' . round($micro * 1000, 4) . " ms");
|
||||
$this->info($message.' | Time: '.$sec.'sec :'.round($micro * 1000, 4).' ms');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Setting;
|
||||
use App\Models\UserBusinessStructure;
|
||||
use App\Models\UserBusiness;
|
||||
use Illuminate\Console\Command;
|
||||
use App\Cron\BusinessUsersStoreOptimized;
|
||||
use App\Cron\UserLevelUpdate;
|
||||
use App\Cron\UserPaymentCredits;
|
||||
use App\Models\Setting;
|
||||
use App\Models\UserBusiness;
|
||||
use App\Models\UserBusinessStructure;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class BusinessStoreOptimized extends Command
|
||||
{
|
||||
|
|
@ -29,10 +29,13 @@ class BusinessStoreOptimized extends Command
|
|||
protected $description = 'Create Business Structure and UserDetails with optimized performance and monitoring';
|
||||
|
||||
private $timeStart;
|
||||
|
||||
private $month;
|
||||
|
||||
private $year;
|
||||
|
||||
private $sendCreditMail = false;
|
||||
|
||||
private $sendUpdateMail = false;
|
||||
|
||||
/**
|
||||
|
|
@ -51,6 +54,58 @@ class BusinessStoreOptimized extends Command
|
|||
$this->sendUpdateMail = $sendUpdateMail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prüft ob der Command heute ausgeführt werden soll
|
||||
*
|
||||
* WICHTIG: Diese Methode verhindert, dass der Command täglich läuft!
|
||||
* Der Command sollte nur am konfigurierten Tag des Monats laufen.
|
||||
*
|
||||
* @return bool True wenn Command ausgeführt werden soll, False sonst
|
||||
*/
|
||||
private function shouldExecuteToday(): bool
|
||||
{
|
||||
// Hole konfigurierten Ausführungstag (Standard: 1 = Monatserster)
|
||||
$executeDay = (int) Setting::getContentBySlug('day-exectute-business-structur');
|
||||
|
||||
// Fallback: Wenn Setting leer oder 0, verwende Tag 1
|
||||
if ($executeDay === 0) {
|
||||
$executeDay = 1;
|
||||
$this->warn('Setting "day-exectute-business-structur" ist leer oder 0. Verwende Standard: Tag 1');
|
||||
\Log::channel('cron')->warning('BusinessStoreOptimized: Setting day-exectute-business-structur is empty, using default: 1');
|
||||
}
|
||||
|
||||
$presentDay = (int) date('d');
|
||||
|
||||
// Logging für Debugging
|
||||
$this->info("BusinessStoreOptimized: Configured Day: {$executeDay}, Present Day: {$presentDay}");
|
||||
\Log::channel('cron')->info("BusinessStoreOptimized: Configured Day: {$executeDay}, Present Day: {$presentDay}");
|
||||
|
||||
// Prüfe ob heute der konfigurierte Tag ist
|
||||
if ($executeDay !== $presentDay) {
|
||||
// Erlaubnis zum Überschreiben für Entwicklung/Testing
|
||||
// ENV-Variable BUSINESS_FORCE_EXECUTE=true überschreibt den Check
|
||||
if (env('BUSINESS_FORCE_EXECUTE', false) === true) {
|
||||
$this->warn('⚠️ BUSINESS_FORCE_EXECUTE ist aktiv - Command wird trotz falschem Tag ausgeführt!');
|
||||
$this->warn('⚠️ Dies sollte NUR auf Test-Servern verwendet werden!');
|
||||
\Log::channel('cron')->warning('BusinessStoreOptimized: FORCED execution via BUSINESS_FORCE_EXECUTE');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Command sollte heute NICHT laufen
|
||||
$this->info("❌ Command wird NICHT ausgeführt - falscher Tag (erwartet: {$executeDay}, heute: {$presentDay})");
|
||||
\Log::channel('cron')->info("BusinessStoreOptimized: NOT EXECUTED - wrong day (expected: {$executeDay}, today: {$presentDay})");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Command wird ausgeführt
|
||||
$this->info("✅ Command wird ausgeführt - korrekter Tag ({$presentDay})");
|
||||
\Log::channel('cron')->info("BusinessStoreOptimized: EXECUTING - correct day ({$presentDay})");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
|
|
@ -69,28 +124,20 @@ class BusinessStoreOptimized extends Command
|
|||
public function handle()
|
||||
{
|
||||
try {
|
||||
$executeDay = (int) Setting::getContentBySlug('day-exectute-business-structur');
|
||||
$presentDay = (int) date('d');
|
||||
|
||||
$this->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;
|
||||
// Prüfe ob Command am richtigen Tag ausgeführt werden soll
|
||||
if (! $this->shouldExecuteToday()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$this->logMemoryUsage('Command Start');
|
||||
|
||||
$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->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->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
|
||||
|
|
@ -126,17 +173,18 @@ class BusinessStoreOptimized extends Command
|
|||
|
||||
return 0;
|
||||
} catch (\Exception $e) {
|
||||
$this->error('Command failed with error: ' . $e->getMessage());
|
||||
$this->error('Stack trace: ' . $e->getTraceAsString());
|
||||
$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);
|
||||
$this->info('storeBusinessStructureUsersDetailMonth month: '.$this->month.' year:'.$this->year);
|
||||
|
||||
try {
|
||||
$businessUsersStore = new BusinessUsersStoreOptimized($this->month, $this->year);
|
||||
|
|
@ -144,16 +192,16 @@ class BusinessStoreOptimized extends Command
|
|||
$businessUsersStore->storeBusinessUsersDetail();
|
||||
$bool = $businessUsersStore->storeBusinessCompleted();
|
||||
|
||||
$this->logExecutionTime('END Command storeBusinessStructureUsersDetailMonth: ' . $bool);
|
||||
$this->logExecutionTime('END Command storeBusinessStructureUsersDetailMonth: '.$bool);
|
||||
} catch (\Exception $e) {
|
||||
$this->error('Error in storeBusinessStructureUsersDetailMonth: ' . $e->getMessage());
|
||||
$this->error('Error in storeBusinessStructureUsersDetailMonth: '.$e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
private function userBusinessCommissionsToCredit()
|
||||
{
|
||||
$this->info('userBusinessCommissionsToCredit month: ' . $this->month . ' year:' . $this->year);
|
||||
$this->info('userBusinessCommissionsToCredit month: '.$this->month.' year:'.$this->year);
|
||||
|
||||
try {
|
||||
$userPaymentCredits = new UserPaymentCredits($this->month, $this->year);
|
||||
|
|
@ -162,7 +210,7 @@ class BusinessStoreOptimized extends Command
|
|||
$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);
|
||||
$this->info('userBusinessCredit: '.$ret->user_id.' : Team: '.$ret->commission_pp_total.' | Shop: '.$ret->commission_shop_sales);
|
||||
$processedCount++;
|
||||
|
||||
// Memory-Check alle 100 User
|
||||
|
|
@ -174,14 +222,14 @@ class BusinessStoreOptimized extends Command
|
|||
$this->info("Processed {$processedCount} user businesses total");
|
||||
$this->logExecutionTime('END Command userBusinessCommissionsToCredit:');
|
||||
} catch (\Exception $e) {
|
||||
$this->error('Error in userBusinessCommissionsToCredit: ' . $e->getMessage());
|
||||
$this->error('Error in userBusinessCommissionsToCredit: '.$e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
private function userCreatePaymentCreditsPDF()
|
||||
{
|
||||
$this->info('userCreatePaymentCreditsPDF month: ' . $this->month . ' year:' . $this->year);
|
||||
$this->info('userCreatePaymentCreditsPDF month: '.$this->month.' year:'.$this->year);
|
||||
|
||||
try {
|
||||
$userPaymentCredits = new UserPaymentCredits($this->month, $this->year);
|
||||
|
|
@ -190,7 +238,7 @@ class BusinessStoreOptimized extends Command
|
|||
$processedCount = 0;
|
||||
foreach ($creditItemUsers as $creditItemUser) {
|
||||
$bool = $userPaymentCredits->makeCreditPaymentPDF($creditItemUser->user_id, $this->sendCreditMail);
|
||||
$this->info('creditsPDF: ' . $bool . ' user_id: ' . $creditItemUser->user_id);
|
||||
$this->info('creditsPDF: '.$bool.' user_id: '.$creditItemUser->user_id);
|
||||
$processedCount++;
|
||||
|
||||
// Memory-Check alle 50 PDFs
|
||||
|
|
@ -202,7 +250,7 @@ class BusinessStoreOptimized extends Command
|
|||
$this->info("Created {$processedCount} PDF files total");
|
||||
$this->logExecutionTime('END Command userCreatePaymentCreditsPDF:');
|
||||
} catch (\Exception $e) {
|
||||
$this->error('Error in userCreatePaymentCreditsPDF: ' . $e->getMessage());
|
||||
$this->error('Error in userCreatePaymentCreditsPDF: '.$e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
|
@ -213,13 +261,13 @@ class BusinessStoreOptimized extends Command
|
|||
*/
|
||||
public function userLevelUpdate()
|
||||
{
|
||||
$this->info('userLevelUpdate month: ' . $this->month . ' year:' . $this->year);
|
||||
$this->info('userLevelUpdate month: '.$this->month.' year:'.$this->year);
|
||||
|
||||
try {
|
||||
$userLevelUpdate = new UserLevelUpdate($this->month, $this->year);
|
||||
$levelUpdateUsers = $userLevelUpdate->getUserBusinessByMonthYear();
|
||||
|
||||
$this->info("Found " . $levelUpdateUsers->count() . " user businesses with level promotions to process");
|
||||
$this->info('Found '.$levelUpdateUsers->count().' user businesses with level promotions to process');
|
||||
|
||||
$updatedCount = 0;
|
||||
$skippedCount = 0;
|
||||
|
|
@ -229,11 +277,11 @@ class BusinessStoreOptimized extends Command
|
|||
try {
|
||||
$ret = $userLevelUpdate->makeUserLevelUpdate($userBusiness, $this->sendUpdateMail);
|
||||
if ($ret) {
|
||||
$oldLevel = $userBusiness->m_level_id . ' ' . ($userBusiness->user_level_name ?? 'N/A');
|
||||
$this->info('updateLevel: User ' . $userBusiness->user->id .
|
||||
' | ' . $userBusiness->user->email .
|
||||
' | from: ' . $oldLevel .
|
||||
' | to: ' . $ret);
|
||||
$oldLevel = $userBusiness->m_level_id.' '.($userBusiness->user_level_name ?? 'N/A');
|
||||
$this->info('updateLevel: User '.$userBusiness->user->id.
|
||||
' | '.$userBusiness->user->email.
|
||||
' | from: '.$oldLevel.
|
||||
' | to: '.$ret);
|
||||
$updatedCount++;
|
||||
} else {
|
||||
$skippedCount++;
|
||||
|
|
@ -241,12 +289,13 @@ class BusinessStoreOptimized extends Command
|
|||
|
||||
// Memory-Check alle 50 User
|
||||
if (($updatedCount + $skippedCount) % 50 === 0) {
|
||||
$this->logMemoryUsage("After processing " . ($updatedCount + $skippedCount) . " users");
|
||||
$this->logMemoryUsage('After processing '.($updatedCount + $skippedCount).' users');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$errorCount++;
|
||||
$this->warn('Error updating level for UserBusiness ' . $userBusiness->id . ': ' . $e->getMessage());
|
||||
\Log::channel('cron')->warning('UserLevelUpdate error for UserBusiness ' . $userBusiness->id . ': ' . $e->getMessage());
|
||||
$this->warn('Error updating level for UserBusiness '.$userBusiness->id.': '.$e->getMessage());
|
||||
\Log::channel('cron')->warning('UserLevelUpdate error for UserBusiness '.$userBusiness->id.': '.$e->getMessage());
|
||||
|
||||
// Weiter mit nächstem User statt abzubrechen
|
||||
continue;
|
||||
}
|
||||
|
|
@ -256,9 +305,9 @@ class BusinessStoreOptimized extends Command
|
|||
$this->logExecutionTime('END Command userLevelUpdate:');
|
||||
$this->logMemoryUsage('After userLevelUpdate');
|
||||
} catch (\Exception $e) {
|
||||
$this->error('Error in userLevelUpdate: ' . $e->getMessage());
|
||||
$this->error('Stack trace: ' . $e->getTraceAsString());
|
||||
\Log::channel('cron')->error('UserLevelUpdate command failed: ' . $e->getMessage());
|
||||
$this->error('Error in userLevelUpdate: '.$e->getMessage());
|
||||
$this->error('Stack trace: '.$e->getTraceAsString());
|
||||
\Log::channel('cron')->error('UserLevelUpdate command failed: '.$e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
|
@ -267,7 +316,7 @@ class BusinessStoreOptimized extends Command
|
|||
{
|
||||
try {
|
||||
for ($i = $from; $i <= $to; $i++) {
|
||||
$this->info('Store Business Structure Users Detail month: ' . $i . ' year:' . $this->year);
|
||||
$this->info('Store Business Structure Users Detail month: '.$i.' year:'.$this->year);
|
||||
$this->logMemoryUsage("Before month {$i}");
|
||||
|
||||
$businessUsersStore = new BusinessUsersStoreOptimized($i, $this->year);
|
||||
|
|
@ -275,11 +324,11 @@ class BusinessStoreOptimized extends Command
|
|||
$businessUsersStore->storeBusinessUsersDetail();
|
||||
$bool = $businessUsersStore->storeBusinessCompleted();
|
||||
|
||||
$this->logExecutionTime('Period BusinessStore: ' . $bool);
|
||||
$this->logExecutionTime('Period BusinessStore: '.$bool);
|
||||
$this->logMemoryUsage("After month {$i}");
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$this->error('Error in storeBusinessStructureUsersDetailPeriod: ' . $e->getMessage());
|
||||
$this->error('Error in storeBusinessStructureUsersDetailPeriod: '.$e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
|
@ -297,8 +346,9 @@ class BusinessStoreOptimized extends Command
|
|||
->where('month', $this->month)
|
||||
->first();
|
||||
|
||||
if (!$existingStructure) {
|
||||
if (! $existingStructure) {
|
||||
$this->info('No stored business structure found to clear');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -322,7 +372,7 @@ class BusinessStoreOptimized extends Command
|
|||
$this->info('Successfully cleared all stored business data');
|
||||
$this->logMemoryUsage('After clearing data');
|
||||
} catch (\Exception $e) {
|
||||
$this->error('Error clearing stored data: ' . $e->getMessage());
|
||||
$this->error('Error clearing stored data: '.$e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
|
@ -333,7 +383,7 @@ class BusinessStoreOptimized extends Command
|
|||
$sec = intval($diff);
|
||||
$micro = $diff - $sec;
|
||||
|
||||
$this->info($message . ' | Time: ' . $sec . 'sec :' . round($micro * 1000, 4) . " ms");
|
||||
$this->info($message.' | Time: '.$sec.'sec :'.round($micro * 1000, 4).' ms');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -353,8 +403,8 @@ class BusinessStoreOptimized extends Command
|
|||
$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());
|
||||
$this->error("Error in {$processName}: ".$e->getMessage());
|
||||
$this->error('Stack trace: '.$e->getTraceAsString());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
|
@ -406,12 +456,12 @@ class BusinessStoreOptimized extends Command
|
|||
*/
|
||||
private function formatBytes(int $bytes, int $precision = 2): string
|
||||
{
|
||||
$units = array('B', 'KB', 'MB', 'GB', 'TB');
|
||||
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
|
||||
for ($i = 0; $bytes > 1024 && $i < count($units) - 1; $i++) {
|
||||
$bytes /= 1024;
|
||||
}
|
||||
|
||||
return round($bytes, $precision) . ' ' . $units[$i];
|
||||
return round($bytes, $precision).' '.$units[$i];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,18 +17,20 @@ class DhlUpdateTracking extends Command
|
|||
* @var string
|
||||
*/
|
||||
protected $signature = 'dhl:update-tracking
|
||||
{--days=14 : Sendungen der letzten X Tage aktualisieren}
|
||||
{--days=30 : Sendungen der letzten X Tage aktualisieren}
|
||||
{--send-emails : Automatisch E-Mails bei Transit-Status senden}
|
||||
{--dry-run : Nur simulieren, keine Änderungen}
|
||||
{--test-email= : Test-E-Mail an angegebene Adresse senden}
|
||||
{--order= : Nur für bestimmte Bestellung (Order-ID)}';
|
||||
{--order= : Nur für bestimmte Bestellung (Order-ID)}
|
||||
{--force : Intervall-Filter überspringen, alle aktiven Sendungen aktualisieren}
|
||||
{--stale-days=30 : Sendungen ohne Statusänderung nach X Tagen als abgeschlossen markieren}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Aktualisiert Tracking-Status für alle aktiven DHL Sendungen und sendet automatisch E-Mails bei Transit-Status';
|
||||
protected $description = 'Aktualisiert Tracking-Status für DHL Sendungen (status-basierte Intervalle, Batch-API)';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
|
|
@ -40,9 +42,14 @@ class DhlUpdateTracking extends Command
|
|||
$dryRun = $this->option('dry-run');
|
||||
$testEmail = $this->option('test-email');
|
||||
$orderId = $this->option('order');
|
||||
$force = $this->option('force');
|
||||
$staleDays = (int) $this->option('stale-days');
|
||||
|
||||
$this->info('DHL Tracking Update gestartet');
|
||||
$this->info("Optionen: --days={$days}, --send-emails=" . ($sendEmails ? 'ja' : 'nein') . ', --dry-run=' . ($dryRun ? 'ja' : 'nein'));
|
||||
$this->info("Optionen: --days={$days}, --send-emails=".($sendEmails ? 'ja' : 'nein')
|
||||
.', --dry-run='.($dryRun ? 'ja' : 'nein')
|
||||
.', --force='.($force ? 'ja' : 'nein')
|
||||
.", --stale-days={$staleDays}");
|
||||
if ($testEmail) {
|
||||
$this->info("Test-Modus: E-Mails werden an {$testEmail} gesendet");
|
||||
}
|
||||
|
|
@ -51,95 +58,185 @@ class DhlUpdateTracking extends Command
|
|||
}
|
||||
$this->newLine();
|
||||
|
||||
// Hole alle aktiven Sendungen der letzten X Tage
|
||||
$query = DhlShipment::active()
|
||||
// Step 1: Mark stale shipments as completed (before main query)
|
||||
$staleCompleted = $this->markStaleShipmentsCompleted($staleDays, $dryRun);
|
||||
|
||||
// Step 2: Build query for shipments that need tracking update
|
||||
$query = $this->buildShipmentQuery($days, $orderId, $force);
|
||||
|
||||
$shipments = $query->orderBy('created_at', 'desc')->get();
|
||||
|
||||
// Count total active shipments for statistics (before interval filter)
|
||||
$totalActive = DhlShipment::active()
|
||||
->whereNull('tracking_completed_at')
|
||||
->where('created_at', '>=', now()->subDays($days))
|
||||
->whereNotNull('dhl_shipment_no');
|
||||
->whereNotNull('dhl_shipment_no')
|
||||
->count();
|
||||
|
||||
$total = $shipments->count();
|
||||
$skippedByInterval = $totalActive - $total;
|
||||
|
||||
$this->info("Aktive Sendungen gesamt: {$totalActive}");
|
||||
$this->info('Übersprungen (Intervall): '.max(0, $skippedByInterval));
|
||||
$this->info("Zu aktualisieren: {$total}");
|
||||
|
||||
if ($total === 0) {
|
||||
$this->info('Keine Sendungen zum Aktualisieren gefunden.');
|
||||
$this->printSummary(0, ['updated' => 0, 'failed' => 0, 'completed' => 0, 'emails_sent' => 0, 'skipped' => 0], $staleCompleted, max(0, $skippedByInterval));
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
$trackingService = new DhlTrackingService;
|
||||
$stats = [
|
||||
'updated' => 0,
|
||||
'failed' => 0,
|
||||
'completed' => 0,
|
||||
'emails_sent' => 0,
|
||||
'skipped' => 0,
|
||||
];
|
||||
|
||||
if ($dryRun) {
|
||||
$stats['skipped'] = $total;
|
||||
$this->info("Dry-Run: {$total} Sendungen würden aktualisiert.");
|
||||
} else {
|
||||
// Collect old statuses for email decision
|
||||
$oldStatuses = $shipments->pluck('status', 'id')->toArray();
|
||||
|
||||
// Use batch API for efficient processing
|
||||
$this->info('Starte Batch-Tracking-Update...');
|
||||
$bar = $this->output->createProgressBar($total);
|
||||
$bar->start();
|
||||
|
||||
$batchResult = $trackingService->updateTrackingBatch($shipments);
|
||||
|
||||
$stats['updated'] = $batchResult['updated'];
|
||||
$stats['failed'] = $batchResult['failed'];
|
||||
$stats['completed'] = $batchResult['completed'];
|
||||
|
||||
$bar->advance($total);
|
||||
$bar->finish();
|
||||
$this->newLine(2);
|
||||
|
||||
// Send tracking emails if enabled
|
||||
if ($sendEmails) {
|
||||
$this->info('Prüfe E-Mail-Versand...');
|
||||
|
||||
foreach ($shipments as $shipment) {
|
||||
$shipment->refresh();
|
||||
$oldStatus = $oldStatuses[$shipment->id] ?? '';
|
||||
|
||||
if ($this->shouldSendEmail($shipment, $oldStatus)) {
|
||||
try {
|
||||
$this->sendTrackingEmail($shipment, $testEmail);
|
||||
$stats['emails_sent']++;
|
||||
} catch (\Exception $e) {
|
||||
Log::error('[DHL Cron] Failed to send tracking email', [
|
||||
'shipment_id' => $shipment->id,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->printSummary($total, $stats, $staleCompleted, max(0, $skippedByInterval));
|
||||
|
||||
Log::info('[DHL Cron] Tracking update completed', array_merge($stats, [
|
||||
'total' => $total,
|
||||
'stale_completed' => $staleCompleted,
|
||||
'skipped_interval' => max(0, $skippedByInterval),
|
||||
]));
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the shipment query with or without interval filtering.
|
||||
*/
|
||||
private function buildShipmentQuery(int $days, ?string $orderId, bool $force)
|
||||
{
|
||||
if ($force) {
|
||||
// --force: Alle aktiven Sendungen ohne Intervall-Filter
|
||||
$query = DhlShipment::active()
|
||||
->whereNull('tracking_completed_at')
|
||||
->where('created_at', '>=', now()->subDays($days))
|
||||
->whereNotNull('dhl_shipment_no');
|
||||
} else {
|
||||
// Normal: Status-basierte Intervalle beachten
|
||||
$query = DhlShipment::needsTrackingUpdate()
|
||||
->where('created_at', '>=', now()->subDays($days));
|
||||
}
|
||||
|
||||
// Filter nach Order-ID wenn angegeben
|
||||
if ($orderId) {
|
||||
$query->where('order_id', $orderId);
|
||||
}
|
||||
|
||||
$shipments = $query->orderBy('created_at', 'desc')->get();
|
||||
return $query;
|
||||
}
|
||||
|
||||
$total = $shipments->count();
|
||||
$this->info("Gefundene aktive Sendungen: {$total}");
|
||||
/**
|
||||
* Mark shipments as tracking-completed if they haven't changed status
|
||||
* for a given number of days (stale shipments).
|
||||
*/
|
||||
private function markStaleShipmentsCompleted(int $staleDays, bool $dryRun): int
|
||||
{
|
||||
$staleShipments = DhlShipment::active()
|
||||
->whereNull('tracking_completed_at')
|
||||
->whereNotNull('last_tracked_at')
|
||||
->where('last_tracked_at', '<', now()->subDays($staleDays))
|
||||
->where('created_at', '<', now()->subDays($staleDays))
|
||||
->get();
|
||||
|
||||
if ($total === 0) {
|
||||
$this->info('Keine Sendungen zum Aktualisieren gefunden.');
|
||||
$count = $staleShipments->count();
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
if ($count > 0) {
|
||||
$this->warn("Veraltete Sendungen gefunden: {$count} (>{$staleDays} Tage ohne Änderung)");
|
||||
|
||||
$bar = $this->output->createProgressBar($total);
|
||||
$bar->start();
|
||||
if (! $dryRun) {
|
||||
foreach ($staleShipments as $shipment) {
|
||||
$shipment->markTrackingCompleted();
|
||||
|
||||
$trackingService = new DhlTrackingService;
|
||||
$stats = [
|
||||
'updated' => 0,
|
||||
'failed' => 0,
|
||||
'emails_sent' => 0,
|
||||
'skipped' => 0,
|
||||
];
|
||||
|
||||
foreach ($shipments as $shipment) {
|
||||
try {
|
||||
$oldStatus = $shipment->status;
|
||||
|
||||
if (! $dryRun) {
|
||||
// Tracking aktualisieren
|
||||
$result = $trackingService->updateTracking($shipment, ['auto_retrack' => false]);
|
||||
|
||||
if ($result['success']) {
|
||||
$shipment->refresh();
|
||||
$stats['updated']++;
|
||||
|
||||
// Prüfen ob E-Mail gesendet werden soll
|
||||
if ($sendEmails && $this->shouldSendEmail($shipment, $oldStatus)) {
|
||||
$this->sendTrackingEmail($shipment, $testEmail);
|
||||
$stats['emails_sent']++;
|
||||
}
|
||||
} else {
|
||||
$stats['failed']++;
|
||||
Log::warning('[DHL Cron] Tracking update failed', [
|
||||
'shipment_id' => $shipment->id,
|
||||
'message' => $result['message'] ?? 'Unknown error',
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
$stats['skipped']++;
|
||||
Log::info('[DHL Cron] Stale shipment tracking completed', [
|
||||
'shipment_id' => $shipment->id,
|
||||
'dhl_shipment_no' => $shipment->dhl_shipment_no,
|
||||
'status' => $shipment->status,
|
||||
'last_tracked_at' => $shipment->last_tracked_at?->toDateTimeString(),
|
||||
]);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$stats['failed']++;
|
||||
Log::error('[DHL Cron] Exception during tracking update', [
|
||||
'shipment_id' => $shipment->id,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
|
||||
$bar->advance();
|
||||
$this->info(" → {$count} Sendungen als Tracking-abgeschlossen markiert.");
|
||||
} else {
|
||||
$this->info(" → Dry-Run: {$count} Sendungen würden als abgeschlossen markiert.");
|
||||
}
|
||||
}
|
||||
|
||||
$bar->finish();
|
||||
$this->newLine(2);
|
||||
$this->newLine();
|
||||
|
||||
// Zusammenfassung
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the final summary table.
|
||||
*/
|
||||
private function printSummary(int $total, array $stats, int $staleCompleted, int $skippedByInterval): void
|
||||
{
|
||||
$this->info('Zusammenfassung:');
|
||||
$this->table(
|
||||
['Metrik', 'Anzahl'],
|
||||
[
|
||||
['Gesamt', $total],
|
||||
['Zu aktualisieren', $total],
|
||||
['Aktualisiert', $stats['updated']],
|
||||
['Fehlgeschlagen', $stats['failed']],
|
||||
['Tracking abgeschlossen', $stats['completed']],
|
||||
['E-Mails gesendet', $stats['emails_sent']],
|
||||
['Übersprungen (Dry-Run)', $stats['skipped']],
|
||||
['Übersprungen (Intervall)', $skippedByInterval],
|
||||
['Veraltet → abgeschlossen', $staleCompleted],
|
||||
]
|
||||
);
|
||||
|
||||
Log::info('[DHL Cron] Tracking update completed', $stats);
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -212,9 +309,9 @@ class DhlUpdateTracking extends Command
|
|||
]);
|
||||
|
||||
if ($allShipments->count() > 1) {
|
||||
$this->line(" -> E-Mail mit {$allShipments->count()} Sendungen gesendet an: {$recipientEmail}");
|
||||
$this->line(" → E-Mail mit {$allShipments->count()} Sendungen gesendet an: {$recipientEmail}");
|
||||
} else {
|
||||
$this->line(" -> E-Mail gesendet an: {$recipientEmail}");
|
||||
$this->line(" → E-Mail gesendet an: {$recipientEmail}");
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
Log::error('[DHL Cron] Failed to send tracking email', [
|
||||
|
|
|
|||
119
app/Console/Commands/FixPaymentLinkStatus.php
Normal file
119
app/Console/Commands/FixPaymentLinkStatus.php
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\ShoppingInstance;
|
||||
use App\Models\ShoppingPayment;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class FixPaymentLinkStatus extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'payment:fix-link-status {--dry-run : Run without making changes}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Fix payment link status for paid orders that have incorrect status in shopping_instances';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$isDryRun = $this->option('dry-run');
|
||||
|
||||
if ($isDryRun) {
|
||||
$this->info(' DRY RUN MODE - No changes will be made');
|
||||
$this->newLine();
|
||||
}
|
||||
|
||||
$this->info('🔎 Searching for payment links with incorrect status...');
|
||||
$this->newLine();
|
||||
|
||||
// Find all ShoppingPayments with identifier that are paid
|
||||
$paidPayments = ShoppingPayment::whereNotNull('identifier')
|
||||
->whereHas('shopping_order', function ($query) {
|
||||
$query->where('paid', 1)
|
||||
->where('txaction', 'paid');
|
||||
})
|
||||
->with(['shopping_order'])
|
||||
->get();
|
||||
|
||||
$this->info("Found {$paidPayments->count()} paid payments with identifiers");
|
||||
$this->newLine();
|
||||
|
||||
$fixed = 0;
|
||||
$skipped = 0;
|
||||
$errors = 0;
|
||||
|
||||
foreach ($paidPayments as $payment) {
|
||||
$identifier = $payment->identifier;
|
||||
|
||||
// Find the corresponding ShoppingInstance
|
||||
$instance = ShoppingInstance::where('identifier', $identifier)->first();
|
||||
|
||||
if (! $instance) {
|
||||
$this->warn("⚠️ ShoppingInstance not found for identifier: {$identifier}");
|
||||
$errors++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if status needs to be updated
|
||||
if ($instance->status < 10) {
|
||||
$oldStatus = $instance->status;
|
||||
$oldStatusName = $instance->getStatus();
|
||||
|
||||
if (! $isDryRun) {
|
||||
$instance->status = 10; // link_paid
|
||||
$instance->save();
|
||||
}
|
||||
|
||||
$this->line(sprintf(
|
||||
'%s Payment #%d: %s → %s (Order #%d, Amount: %s)',
|
||||
$isDryRun ? '📋' : '✅',
|
||||
$payment->id,
|
||||
$oldStatusName." ($oldStatus)",
|
||||
'link_paid (10)',
|
||||
$payment->shopping_order_id,
|
||||
$payment->getPaymentAmount()
|
||||
));
|
||||
|
||||
$fixed++;
|
||||
} else {
|
||||
$skipped++;
|
||||
}
|
||||
}
|
||||
|
||||
$this->newLine();
|
||||
$this->info('📊 Summary:');
|
||||
$this->table(
|
||||
['Status', 'Count'],
|
||||
[
|
||||
['Fixed/Would fix', $fixed],
|
||||
['Already correct', $skipped],
|
||||
['Errors', $errors],
|
||||
['Total processed', $paidPayments->count()],
|
||||
]
|
||||
);
|
||||
|
||||
if ($isDryRun && $fixed > 0) {
|
||||
$this->newLine();
|
||||
$this->warn('⚠️ This was a DRY RUN. Run without --dry-run to apply changes.');
|
||||
}
|
||||
|
||||
if (! $isDryRun && $fixed > 0) {
|
||||
$this->newLine();
|
||||
$this->info("✨ Successfully updated {$fixed} payment link(s)!");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,17 +2,14 @@
|
|||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Services\UserUtil;
|
||||
use App\User;
|
||||
use Carbon\Carbon;
|
||||
use App\Services\UserUtil;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
|
||||
class UserCleanUp extends Command
|
||||
{
|
||||
/**
|
||||
* ln -sfv /usr/bin/php73 /usr/bin/php
|
||||
* php74 artisan user:cleanup
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
|
|
@ -24,7 +21,8 @@ class UserCleanUp extends Command
|
|||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'User Clean Up inactive for Business Structur and UserDetails';
|
||||
protected $description = 'User Clean Up inactive for Business Structure and UserDetails';
|
||||
|
||||
private $timeStart;
|
||||
|
||||
/**
|
||||
|
|
@ -44,118 +42,162 @@ class UserCleanUp extends Command
|
|||
*/
|
||||
public function handle()
|
||||
{
|
||||
|
||||
$this->info('RUN Command user:cleanup');
|
||||
\Log::channel('cleanup')->info('COMMAND [user:cleanup] started.');
|
||||
|
||||
$this->timeStart = microtime(true);
|
||||
|
||||
$this->deleteInavtiveUsers();
|
||||
//alle inaktive User werden deaktivert, die childs werden dem nächsten aktiven Berater (parent) zugewiesen.
|
||||
// Schritt 1: User löschen, die länger als 2 Monate inaktiv sind
|
||||
$this->deleteInactiveUsers();
|
||||
|
||||
// Schritt 2: Alle inaktiven User deaktivieren (länger als 2 Wochen inaktiv)
|
||||
// Ihre Downline wird dem nächsten aktiven Berater (Sponsor) zugewiesen
|
||||
$this->cleanUpInActiveUser();
|
||||
|
||||
return 0;
|
||||
|
||||
\Log::channel('cleanup')->info('COMMAND [user:cleanup] finished.');
|
||||
//return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//gibt es gelöschte Berater mit Kunden und childs???
|
||||
|
||||
private function deleteInavtiveUsers()
|
||||
/**
|
||||
* Löscht User, die länger als 2 Monate inaktiv sind (payment_account < -2 month)
|
||||
* - Weist deren Vertriebspartner-Kinder dem nächsten aktiven Sponsor zu
|
||||
* - Überträgt deren Shopping-Kunden zum neuen Sponsor
|
||||
* - Konvertiert den User zu einem Shopping-Kunden
|
||||
* - Löscht den User (soft delete)
|
||||
*/
|
||||
private function deleteInactiveUsers()
|
||||
{
|
||||
|
||||
$this->info('START Command deleteInavtiveUsers');
|
||||
$methodStartTime = microtime(true);
|
||||
$this->info('START Command deleteInactiveUsers');
|
||||
$count = 0;
|
||||
|
||||
$date = Carbon::now()->modify('-2 month');
|
||||
$delete_users = User::where('admin', 0)->where('payment_account', '<', $date)->get();
|
||||
|
||||
foreach ($delete_users as $delete_user) {
|
||||
/*
|
||||
dump('delete_users ---------- ');
|
||||
dump($delete_user->id);
|
||||
dump($delete_user->email);
|
||||
*/
|
||||
//finde nächsten aktiven Sponsor $delete_user->id kann sponsor oder pre sponsor sein
|
||||
$active_sponsor = UserUtil::findNextActiveSponsor($delete_user->id);
|
||||
if ($active_sponsor) {
|
||||
//setze alle Berater vom Sponsor für alle childs
|
||||
\DB::beginTransaction();
|
||||
|
||||
try {
|
||||
// Finde nächsten aktiven Sponsor
|
||||
$active_sponsor = UserUtil::findNextActiveSponsor($delete_user->id);
|
||||
|
||||
if (! $active_sponsor) {
|
||||
\Log::channel('cleanup')->error('deleteInactiveUsers find no active_sponsor by delete_user_id: '.$delete_user->id);
|
||||
\DB::rollBack();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Prüfe ob User Account-Daten hat
|
||||
if (! $delete_user->account) {
|
||||
\Log::channel('cleanup')->error('deleteInactiveUsers: User has no account data, skipping user_id: '.$delete_user->id);
|
||||
\DB::rollBack();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Setze alle Vertriebspartner-Kinder zum neuen Sponsor
|
||||
UserUtil::setNewSponsorToChilds($delete_user->id, $active_sponsor->id);
|
||||
|
||||
// Übertrage Shopping-User zum neuen Sponsor
|
||||
UserUtil::setShoppingUserToNewMember($delete_user->id, $active_sponsor->id);
|
||||
} else {
|
||||
\Log::channel('cleanup')->error('deleteInavtiveUsers find no active_sponsor by delete_user_id:' . $delete_user->id);
|
||||
|
||||
// Konvertiere User zu Client beim neuen Sponsor
|
||||
UserUtil::setUserToClient($delete_user->id, $active_sponsor->id);
|
||||
|
||||
$data = [
|
||||
'user_id' => $delete_user->id,
|
||||
'email' => $delete_user->email,
|
||||
'm_account' => $delete_user->account->m_account,
|
||||
'm_first_name' => $delete_user->account->m_first_name,
|
||||
'm_last_name' => $delete_user->account->m_last_name,
|
||||
];
|
||||
|
||||
// Lösche User (soft delete)
|
||||
UserUtil::deleteUser($delete_user);
|
||||
|
||||
\DB::commit();
|
||||
$count++;
|
||||
\Log::channel('cleanup')->info('deleteUser: '.json_encode($data));
|
||||
} catch (\Exception $e) {
|
||||
\DB::rollBack();
|
||||
\Log::channel('cleanup')->error('deleteInactiveUsers failed for user_id: '.$delete_user->id.' | Error: '.$e->getMessage());
|
||||
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
dump('findNextActiveSponsor');
|
||||
dump($active_sponsor->email);
|
||||
*/
|
||||
//make User to an Client from sponsor and delete User
|
||||
UserUtil::setUserToClient($delete_user->id, $active_sponsor->id);
|
||||
|
||||
$data = [
|
||||
'user_id' => $delete_user->id,
|
||||
'email' => $delete_user->email,
|
||||
'm_account' => $delete_user->account ? $delete_user->account->m_account : '',
|
||||
'm_first_name' => $delete_user->account ? $delete_user->account->m_first_name : '',
|
||||
'm_last_name' => $delete_user->account ? $delete_user->account->m_last_name : '',
|
||||
];
|
||||
$count++;
|
||||
\Log::channel('cleanup')->info('deleteUser: ' . json_encode($data));
|
||||
UserUtil::deleteUser($delete_user);
|
||||
}
|
||||
|
||||
$diff = microtime(true) - $this->timeStart;
|
||||
$diff = microtime(true) - $methodStartTime;
|
||||
$sec = intval($diff);
|
||||
$micro = $diff - $sec;
|
||||
|
||||
$this->info('END Command deleteInavtiveUsers: ' . $count . ' | Time: ' . $sec . 'sec :' . round($micro * 1000, 4) . " ms");
|
||||
$this->info('END Command deleteInactiveUsers: '.$count.' | Time: '.$sec.'sec :'.round($micro * 1000, 4).' ms');
|
||||
}
|
||||
|
||||
/**
|
||||
* Deaktiviert User, die länger als 2 Wochen inaktiv sind
|
||||
* - Weist deren Vertriebspartner-Kinder dem nächsten aktiven Sponsor zu
|
||||
* - Deaktiviert den User (behält Account, speichert Sponsor in pre_sponsor)
|
||||
* - Shopping-Kunden werden NICHT übertragen (bleiben beim deaktivierten User)
|
||||
*/
|
||||
private function cleanUpInActiveUser()
|
||||
{
|
||||
|
||||
$methodStartTime = microtime(true);
|
||||
$this->info('START Command cleanUpInActiveUser');
|
||||
$count = 0;
|
||||
|
||||
//clean up user where inactive since 2 weeks
|
||||
// Finde User die länger als 2 Wochen inaktiv sind
|
||||
$date = Carbon::now()->modify('-2 weeks');
|
||||
|
||||
$inactive_users = User::where('active', true)->where('m_sponsor', '!=', null)->where('payment_account', '<', $date)->get();
|
||||
foreach ($inactive_users as $inactive_user) {
|
||||
/*
|
||||
dump('inactive_user ---------- ');
|
||||
dump($inactive_user->id);
|
||||
dump($inactive_user->email);
|
||||
*/
|
||||
$active_sponsor = UserUtil::findNextActiveSponsor($inactive_user->m_sponsor);
|
||||
if ($active_sponsor) {
|
||||
UserUtil::setNewSponsorToChilds($inactive_user->id, $active_sponsor->id);
|
||||
} else {
|
||||
\Log::channel('cleanup')->error('cleanUpInActiveUser find no active_sponsor by inactive_user:' . $inactive_user->id);
|
||||
}
|
||||
/*
|
||||
dump('findNextActiveSponsor');
|
||||
dump($active_sponsor->email);
|
||||
*/
|
||||
$data = [
|
||||
'user_id' => $inactive_user->id,
|
||||
'email' => $inactive_user->email,
|
||||
'm_account' => $inactive_user->account ? $inactive_user->account->m_account : '',
|
||||
'm_first_name' => $inactive_user->account ? $inactive_user->account->m_first_name : '',
|
||||
'm_last_name' => $inactive_user->account ? $inactive_user->account->m_last_name : '',
|
||||
];
|
||||
$count++;
|
||||
$inactive_users = User::where('active', true)
|
||||
->where('m_sponsor', '!=', null)
|
||||
->where('payment_account', '<', $date)
|
||||
->get();
|
||||
|
||||
\Log::channel('cleanup')->info('inactive_user: ' . json_encode($data));
|
||||
UserUtil::deactiveUser($inactive_user);
|
||||
foreach ($inactive_users as $inactive_user) {
|
||||
\DB::beginTransaction();
|
||||
|
||||
try {
|
||||
// Finde nächsten aktiven Sponsor
|
||||
$active_sponsor = UserUtil::findNextActiveSponsor($inactive_user->m_sponsor);
|
||||
|
||||
if (! $active_sponsor) {
|
||||
\Log::channel('cleanup')->error('cleanUpInActiveUser find no active_sponsor by inactive_user: '.$inactive_user->id);
|
||||
\DB::rollBack();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Setze alle Vertriebspartner-Kinder zum neuen Sponsor
|
||||
UserUtil::setNewSponsorToChilds($inactive_user->id, $active_sponsor->id);
|
||||
|
||||
$data = [
|
||||
'user_id' => $inactive_user->id,
|
||||
'email' => $inactive_user->email,
|
||||
'm_account' => $inactive_user->account ? $inactive_user->account->m_account : '',
|
||||
'm_first_name' => $inactive_user->account ? $inactive_user->account->m_first_name : '',
|
||||
'm_last_name' => $inactive_user->account ? $inactive_user->account->m_last_name : '',
|
||||
];
|
||||
|
||||
// Deaktiviere User (setzt pre_sponsor, entfernt m_sponsor, setzt active=false)
|
||||
UserUtil::deactiveUser($inactive_user);
|
||||
|
||||
\DB::commit();
|
||||
$count++;
|
||||
\Log::channel('cleanup')->info('inactive_user: '.json_encode($data));
|
||||
} catch (\Exception $e) {
|
||||
\DB::rollBack();
|
||||
\Log::channel('cleanup')->error('cleanUpInActiveUser failed for user_id: '.$inactive_user->id.' | Error: '.$e->getMessage());
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$diff = microtime(true) - $this->timeStart;
|
||||
$diff = microtime(true) - $methodStartTime;
|
||||
$sec = intval($diff);
|
||||
$micro = $diff - $sec;
|
||||
|
||||
$this->info('END Command cleanUpInActiveUser: ' . $count . ' | Time: ' . $sec . 'sec :' . round($micro * 1000, 4) . " ms");
|
||||
$this->info('END Command cleanUpInActiveUser: '.$count.' | Time: '.$sec.'sec :'.round($micro * 1000, 4).' ms');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,17 +2,13 @@
|
|||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\User;
|
||||
use Carbon\Carbon;
|
||||
use App\Services\UserUtil;
|
||||
use App\User;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
|
||||
class UserRestore extends Command
|
||||
{
|
||||
/**
|
||||
* ln -sfv /usr/bin/php73 /usr/bin/php
|
||||
* php artisan user:restore {user_id}
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
|
|
@ -24,9 +20,9 @@ class UserRestore extends Command
|
|||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'User Restore active User where inactive for Business Structur and UserDetails';
|
||||
protected $description = 'User Restore: Reactivates an inactive user and restores their downline structure';
|
||||
|
||||
private $timeStart;
|
||||
private $user_id;
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
|
|
@ -45,68 +41,95 @@ class UserRestore extends Command
|
|||
*/
|
||||
public function handle()
|
||||
{
|
||||
|
||||
$this->info('RUN Command user:restore');
|
||||
\Log::channel('cleanup')->info('COMMAND [user:restore] started.');
|
||||
|
||||
$this->timeStart = microtime(true);
|
||||
|
||||
$this->restoreInavtiveUsers();
|
||||
return 0;
|
||||
|
||||
//\Log::info('Cron is running');
|
||||
//return 0;
|
||||
$result = $this->restoreInactiveUsers();
|
||||
|
||||
\Log::channel('cleanup')->info('COMMAND [user:restore] finished.');
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
//gibt es gelöschte Berater mit Kunden und childs???
|
||||
|
||||
private function restoreInavtiveUsers(){
|
||||
/**
|
||||
* Stellt einen deaktivierten User wieder her
|
||||
* - Reaktiviert den User (setzt active=true, stellt m_sponsor wieder her)
|
||||
* - Stellt die Vertriebspartner-Kinder (Downline) wieder her
|
||||
* - Nutzt UserCleanUpLog um die ursprüngliche Struktur wiederherzustellen
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function restoreInactiveUsers()
|
||||
{
|
||||
$methodStartTime = microtime(true);
|
||||
$this->info('START Command restoreInactiveUsers');
|
||||
|
||||
$this->info('START Command restoreInavtiveUsers');
|
||||
$count = 0;
|
||||
$user_id = $this->argument('user_id');
|
||||
|
||||
$this->user_id = $this->argument('user_id');
|
||||
if (! $user_id) {
|
||||
$this->error('ERROR: No user_id provided as argument');
|
||||
\Log::channel('cleanup')->error('restoreInactiveUsers: No user_id provided');
|
||||
|
||||
if(!$this->user_id){
|
||||
$this->info('NO user_id as argument');
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
|
||||
$this->info('RUN Command restoreInavtiveUsers on user_id: '.$this->user_id);
|
||||
$this->info('Restoring user with ID: '.$user_id);
|
||||
|
||||
$user = User::find($this->user_id);
|
||||
$user = User::find($user_id);
|
||||
|
||||
if (! $user) {
|
||||
$this->error('ERROR: User not found with ID: '.$user_id);
|
||||
\Log::channel('cleanup')->error('restoreInactiveUsers: User not found, user_id: '.$user_id);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Prüfe ob User bereits aktiv ist
|
||||
if ($user->active) {
|
||||
$this->warn('WARNING: User is already active, user_id: '.$user_id);
|
||||
\Log::channel('cleanup')->warning('restoreInactiveUsers: User is already active, user_id: '.$user_id);
|
||||
|
||||
if(!$user){
|
||||
$this->info('restoreInavtiveUsers find no user by user_id:'.$this->user_id);
|
||||
\Log::channel('cleanup')->error('restoreInavtiveUsers find no user by user_id:'.$this->user_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'user_id' => $user->id,
|
||||
'email' => $user->email,
|
||||
'm_account' => $user->account ? $user->account->m_account : '',
|
||||
'm_first_name' => $user->account ? $user->account->m_first_name : '',
|
||||
'm_last_name' => $user->account ? $user->account->m_last_name : '',
|
||||
];
|
||||
\Log::channel('cleanup')->info('reactiveUser: '.json_encode($data));
|
||||
\DB::beginTransaction();
|
||||
|
||||
UserUtil::reactiveUser($user);
|
||||
//childs wieder herstellen
|
||||
UserUtil::resetChildsToSponsor($user->id);
|
||||
try {
|
||||
$data = [
|
||||
'user_id' => $user->id,
|
||||
'email' => $user->email,
|
||||
'm_account' => $user->account ? $user->account->m_account : '',
|
||||
'm_first_name' => $user->account ? $user->account->m_first_name : '',
|
||||
'm_last_name' => $user->account ? $user->account->m_last_name : '',
|
||||
];
|
||||
|
||||
// Reaktiviere User (setzt active=true, stellt m_sponsor aus pre_sponsor wieder her)
|
||||
UserUtil::reactiveUser($user);
|
||||
|
||||
$diff = microtime(true) - $this->timeStart;
|
||||
$sec = intval($diff);
|
||||
$micro = $diff - $sec;
|
||||
// Stelle alle Vertriebspartner-Kinder wieder her
|
||||
UserUtil::resetChildsToSponsor($user->id);
|
||||
|
||||
$this->info('END Command deleteInavtiveUsers: '.$count. ' | Time: '.$sec. 'sec :' . round($micro * 1000, 4) . " ms");
|
||||
\DB::commit();
|
||||
|
||||
$diff = microtime(true) - $methodStartTime;
|
||||
$sec = intval($diff);
|
||||
$micro = $diff - $sec;
|
||||
|
||||
$this->info('SUCCESS: User restored successfully');
|
||||
$this->info('END Command restoreInactiveUsers | Time: '.$sec.'sec :'.round($micro * 1000, 4).' ms');
|
||||
|
||||
\Log::channel('cleanup')->info('restoreInactiveUsers SUCCESS: '.json_encode($data));
|
||||
|
||||
return 0;
|
||||
} catch (\Exception $e) {
|
||||
\DB::rollBack();
|
||||
|
||||
$this->error('ERROR: Failed to restore user: '.$e->getMessage());
|
||||
\Log::channel('cleanup')->error('restoreInactiveUsers FAILED for user_id: '.$user_id.' | Error: '.$e->getMessage());
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//497
|
||||
|
||||
//489 -> de
|
||||
|
||||
//478 new
|
||||
Loading…
Add table
Add a link
Reference in a new issue