diff --git a/src/app/Console/Commands/Wallet/BalancesCommand.php b/src/app/Console/Commands/Wallet/BalancesCommand.php --- a/src/app/Console/Commands/Wallet/BalancesCommand.php +++ b/src/app/Console/Commands/Wallet/BalancesCommand.php @@ -2,7 +2,10 @@ namespace App\Console\Commands\Wallet; +use App\Transaction; +use App\Wallet; use Illuminate\Console\Command; +use Illuminate\Support\Facades\DB; class BalancesCommand extends Command { @@ -11,7 +14,7 @@ * * @var string */ - protected $signature = 'wallet:balances'; + protected $signature = 'wallet:balances {--skip-zeros} {--negative} {--invalid}'; /** * The console command description. @@ -27,27 +30,52 @@ */ public function handle() { - $wallets = \App\Wallet::select('wallets.*') + $skip_zeros = $this->option('skip-zeros'); + $negative = $this->option('negative'); + $invalid = $this->option('invalid'); + + $wallets = Wallet::select('wallets.*', 'users.email') ->join('users', 'users.id', '=', 'wallets.user_id') ->withEnvTenantContext('users') - ->where('balance', '!=', '0') ->whereNull('users.deleted_at') ->orderBy('balance'); - $wallets->each( - function ($wallet) { - $user = $wallet->owner; - - $this->info( - sprintf( - "%s: %8s (account: %s/%s (%s))", - $wallet->id, - $wallet->balance, - "https://kolabnow.com/cockpit/admin/accounts/show", - $user->id, - $user->email - ) - ); + if ($invalid) { + $balances = Transaction::select(DB::raw('sum(amount) as summary, object_id as wallet_id')) + ->where('object_type', Wallet::class) + ->groupBy('wallet_id'); + + $wallets->addSelect('balances.summary') + ->leftJoinSub($balances, 'balances', function ($join) { + $join->on('wallets.id', '=', 'balances.wallet_id'); + }) + ->whereRaw('(balances.summary != wallets.balance or (balances.summary is null and wallets.balance != 0))'); + + if ($negative) { + $wallets->where('balances.summary', '<', 0); + } elseif ($skip_zeros) { + $wallets->whereRaw('balances.summary != 0 and balances.summary is not null'); + } + } else { + if ($negative) { + $wallets->where('wallets.balance', '<', 0); + } elseif ($skip_zeros) { + $wallets->whereNot('wallets.balance', 0); + } + } + + $wallets->cursor()->each( + function (Wallet $wallet) use ($invalid) { + $balance = $wallet->balance; + $summary = $wallet->summary ?? 0; + $email = $wallet->email; // @phpstan-ignore-line + + if ($invalid) { + $this->info(sprintf("%s: %8s %8s (%s)", $wallet->id, $balance, $summary, $email)); + return; + } + + $this->info(sprintf("%s: %8s (%s)", $wallet->id, $balance, $email)); } ); } diff --git a/src/tests/Feature/Console/Wallet/BalancesTest.php b/src/tests/Feature/Console/Wallet/BalancesTest.php --- a/src/tests/Feature/Console/Wallet/BalancesTest.php +++ b/src/tests/Feature/Console/Wallet/BalancesTest.php @@ -15,6 +15,9 @@ parent::setUp(); $this->deleteTestUser('wallets-controller@kolabnow.com'); + + \App\Wallet::query()->update(['balance' => 0]); + \App\Transaction::truncate(); } /** @@ -37,26 +40,36 @@ $user = $this->getTestUser('wallets-controller@kolabnow.com'); $wallet = $user->wallets()->first(); - // Expect no wallets with balance=0 - $code = \Artisan::call("wallet:balances"); + // Expect no wallets with balance=0 when using --negative + $code = \Artisan::call("wallet:balances --negative"); $output = trim(\Artisan::output()); $this->assertSame(0, $code); - $this->assertTrue(strpos($output, $wallet->id) === false); + $this->assertSame('', $output); $wallet->balance = -100; $wallet->save(); // Expect the wallet with a negative balance in output - $code = \Artisan::call("wallet:balances"); + $code = \Artisan::call("wallet:balances --negative"); + $output = trim(\Artisan::output()); + + $this->assertSame(0, $code); + $this->assertStringContainsString("{$wallet->id}: -100 ({$user->email})", $output); + + // Test --skip-zeros + $code = \Artisan::call("wallet:balances --skip-zeros"); + $output = trim(\Artisan::output()); + + $this->assertSame(0, $code); + $this->assertSame("{$wallet->id}: -100 ({$user->email})", $output); + + // Test --invalid + $code = \Artisan::call("wallet:balances --invalid"); $output = trim(\Artisan::output()); $this->assertSame(0, $code); - $this->assertMatchesRegularExpression( - '|' . preg_quote($wallet->id, '|') . ': {5}-100 \(account: https://.*/admin/accounts/show/' - . $user->id . ' \(' . preg_quote($user->email, '|') . '\)\)|', - $output - ); + $this->assertSame("{$wallet->id}: -100 0 ({$user->email})", $output); $user->delete();