diff --git a/src/app/Observers/UserObserver.php b/src/app/Observers/UserObserver.php --- a/src/app/Observers/UserObserver.php +++ b/src/app/Observers/UserObserver.php @@ -116,18 +116,6 @@ if (\App\Tenant::getConfig($user->tenant_id, 'pgp.enable')) { \App\Jobs\PGP\KeyDeleteJob::dispatch($user->id, $user->email); } - - // Debit the reseller's wallet with the user negative balance - $balance = 0; - foreach ($user->wallets as $wallet) { - // Note: here we assume all user wallets are using the same currency. - // It might get changed in the future - $balance += $wallet->balance; - } - - if ($balance < 0 && $user->tenant && ($wallet = $user->tenant->wallet())) { - $wallet->debit($balance * -1, "Deleted user {$user->email}"); - } } } diff --git a/src/app/Wallet.php b/src/app/Wallet.php --- a/src/app/Wallet.php +++ b/src/app/Wallet.php @@ -92,6 +92,7 @@ $transactions = []; $profit = 0; $charges = 0; + $fees = 0; $isDegraded = $this->owner->isDegraded(); $trial = $this->trialInfo(); @@ -119,15 +120,14 @@ // Calculate cost, fee, and end of period [$cost, $fee, $endDate] = $this->entitlementCosts($entitlement, $trial); - // Note: Degraded pays nothing, but we get the money from a tenant. - // Therefore $cost = 0, but $profit < 0. + // No balance changes for degraded users if ($isDegraded) { $cost = 0; + } else { + $charges += $cost; + $fees += $fee; } - $charges += $cost; - $profit += $cost - $fee; - // if we're in dry-run, you know... if (!$apply) { continue; @@ -145,7 +145,12 @@ $transactions[] = $entitlement->createTransaction(Transaction::ENTITLEMENT_BILLED, $cost); } + if ($apply) { + // limit profit by wallet balance so a reseller can't build profit by users building debt + $profit = min($charges, $this->balance); + // We always take the full fee + $profit -= $fees; $this->debit($charges, '', $transactions)->addTenantProfit($profit); DB::commit(); @@ -538,6 +543,7 @@ { $charges = 0; $profit = 0; + $fees = 0; $trial = $this->trialInfo(); DB::beginTransaction(); @@ -550,10 +556,12 @@ // Calculate cost, fee, and end of period [$cost, $fee, $endDate] = $this->entitlementCosts($entitlement, $trial, true); - // Note: Degraded pays nothing, but we get the money from a tenant. - // Therefore $cost = 0, but $profit < 0. + // No balance changes for degraded users if (!$withCost) { $cost = 0; + } else { + $charges += $cost; + $fees += $fee; } if ($endDate) { @@ -561,9 +569,6 @@ $entitlement->save(); } - $charges += $cost; - $profit += $cost - $fee; - if ($cost == 0) { continue; } @@ -572,6 +577,10 @@ $transactions[] = $entitlement->createTransaction(Transaction::ENTITLEMENT_BILLED, $cost); } + // limit profit by wallet balance so a reseller can't build profit by users building debt + $profit = min($charges, $this->balance); + // We always take the full fee + $profit -= $fees; $this->debit($charges, '', $transactions)->addTenantProfit($profit); DB::commit(); @@ -619,6 +628,14 @@ $amount = abs($amount) * -1; } + if ($this->balance < 0 && ($this->balance + $amount) > 0) { + // We already took our fee when the wallet went below 0 + // TODO a bonus topup could result in reseller wallet balance, which we don't want I think. + // But I suppose that's a fundamental of paying out a percentage of wallet credit, and not payments. + $negativeBalance = abs($this->balance); + $this->addTenantProfit($negativeBalance); + } + $this->balance += $amount; $this->save();