diff --git a/src/app/Http/Controllers/API/V4/PaymentsController.php b/src/app/Http/Controllers/API/V4/PaymentsController.php --- a/src/app/Http/Controllers/API/V4/PaymentsController.php +++ b/src/app/Http/Controllers/API/V4/PaymentsController.php @@ -198,16 +198,9 @@ // Validate the minimum value // It has to be at least minimum payment amount and must cover current debt, // and must be more than a yearly/monthly payment (according to the plan) - $min = Payment::MIN_AMOUNT; + $min = $wallet->getMinMandateAmount(); $label = 'minamount'; - if (($plan = $wallet->plan()) && $plan->months >= 1) { - $planCost = $plan->cost() * $plan->months; - if ($planCost > $min) { - $min = $planCost; - } - } - if ($wallet->balance < 0 && $wallet->balance < $min * -1) { $min = $wallet->balance * -1; $label = 'minamountdebt'; @@ -436,7 +429,7 @@ // Get the Mandate info $mandate = (array) $provider->getMandate($wallet); - $mandate['amount'] = $mandate['minAmount'] = (int) ceil(Payment::MIN_AMOUNT / 100); + $mandate['amount'] = $mandate['minAmount'] = round($wallet->getMinMandateAmount() / 100, 2); $mandate['balance'] = 0; $mandate['isDisabled'] = !empty($mandate['id']) && $settings['mandate_disabled']; $mandate['isValid'] = !empty($mandate['isValid']); @@ -447,14 +440,6 @@ } } - // If this is a multi-month plan, we calculate the expected amount to be payed. - if (($plan = $wallet->plan()) && $plan->months >= 1) { - $planCost = round($plan->cost() * $plan->months / 100, 2); - if ($planCost > $mandate['minAmount']) { - $mandate['minAmount'] = $planCost; - } - } - // Unrestrict the wallet owner if mandate is valid if (!empty($mandate['isValid']) && $wallet->owner->isRestricted()) { $wallet->owner->unrestrict(); diff --git a/src/app/Wallet.php b/src/app/Wallet.php --- a/src/app/Wallet.php +++ b/src/app/Wallet.php @@ -420,11 +420,9 @@ /** * Return the exact, numeric version of the discount to be applied. * - * Ranges from 0 - 100. - * - * @return int + * @return int Discount in percent, ranges from 0 - 100. */ - public function getDiscount() + public function getDiscount(): int { return $this->discount ? $this->discount->discount : 0; } @@ -432,14 +430,34 @@ /** * The actual discount rate for use in multiplication * - * Ranges from 0.00 to 1.00. + * @return float Discount rate, ranges from 0.00 to 1.00. */ - public function getDiscountRate() + public function getDiscountRate(): float { return (100 - $this->getDiscount()) / 100; } /** + * The minimum amount of an auto-payment mandate + * + * @return int Amount in cents + */ + public function getMinMandateAmount(): int + { + $min = Payment::MIN_AMOUNT; + + if ($plan = $this->plan()) { + $planCost = (int) ($plan->cost() * $plan->months * $this->getDiscountRate()); + + if ($planCost > $min) { + $min = $planCost; + } + } + + return $min; + } + + /** * Check if the specified user is a controller to this wallet. * * @param \App\User $user The user object. diff --git a/src/tests/Feature/WalletTest.php b/src/tests/Feature/WalletTest.php --- a/src/tests/Feature/WalletTest.php +++ b/src/tests/Feature/WalletTest.php @@ -2,6 +2,7 @@ namespace Tests\Feature; +use App\Discount; use App\Payment; use App\Package; use App\Plan; @@ -59,6 +60,7 @@ Sku::select()->update(['fee' => 0]); Payment::query()->delete(); VatRate::query()->delete(); + Plan::withEnvTenantContext()->where('title', 'individual')->update(['months' => 1]); parent::tearDown(); } @@ -279,7 +281,7 @@ /** * Verify a wallet can be assigned a controller. */ - public function testAddWalletController(): void + public function testAddController(): void { $userA = $this->getTestUser('WalletControllerA@WalletController.com'); $userB = $this->getTestUser('WalletControllerB@WalletController.com'); @@ -299,6 +301,35 @@ } /** + * Test Wallet::getMinMandateAmount() + */ + public function testGetMinMandateAmount(): void + { + $user = $this->getTestUser('WalletControllerA@WalletController.com'); + $user->setSetting('plan_id', null); + $wallet = $user->wallets()->first(); + + // No plan assigned + $this->assertSame(Payment::MIN_AMOUNT, $wallet->getMinMandateAmount()); + + // Plan assigned + $plan = Plan::withEnvTenantContext()->where('title', 'individual')->first(); + $plan->months = 12; + $plan->save(); + + $user->setSetting('plan_id', $plan->id); + + $this->assertSame(990 * 12, $wallet->getMinMandateAmount()); + + // Plan and discount + $discount = Discount::where('discount', 30)->first(); + $wallet->discount()->associate($discount); + $wallet->save(); + + $this->assertSame((int) (990 * 12 * 0.70), $wallet->getMinMandateAmount()); + } + + /** * Test Wallet::isController() */ public function testIsController(): void