diff --git a/src/app/Http/Controllers/API/SignupController.php b/src/app/Http/Controllers/API/SignupController.php --- a/src/app/Http/Controllers/API/SignupController.php +++ b/src/app/Http/Controllers/API/SignupController.php @@ -364,6 +364,13 @@ $login = Str::lower($request->login); $domain_name = Str::lower($request->domain); $domain = null; + $user_status = User::STATUS_RESTRICTED; + + if ($request->discount && $request->discount->discount == 100 + && $request->plan->mode == Plan::MODE_MANDATE + ) { + $user_status = User::STATUS_ACTIVE; + } DB::beginTransaction(); @@ -379,7 +386,7 @@ $user = User::create([ 'email' => $login . '@' . $domain_name, 'password' => $request->password, - 'status' => User::STATUS_RESTRICTED, + 'status' => $user_status, ]); if ($request->discount) { @@ -435,6 +442,15 @@ $disc = 0; if ($discount) { + // Free accounts don't need the auto-payment mandate + // Note: This means the voucher code is the only point of user verification + if ($discount->discount == 100) { + return [ + 'content' => self::trans('app.signup-account-free'), + 'cost' => 0, + ]; + } + $planCost = (int) ($planCost * (100 - $discount->discount) / 100); $disc = $cost - $planCost; } @@ -513,6 +529,7 @@ $result['title'] = self::trans("app.signup-plan-{$period}"); $result['content'] = self::trans('app.signup-account-mandate', $params); $result['summary'] = '' . $summary . '
'; + $result['cost'] = $planCost; return $result; } diff --git a/src/resources/lang/en/app.php b/src/resources/lang/en/app.php --- a/src/resources/lang/en/app.php +++ b/src/resources/lang/en/app.php @@ -132,6 +132,7 @@ 'signup-account-mandate' => 'Now it is required to provide your credit card details.' . ' This way you agree to charge you with an appropriate amount of money according to the plan you signed up for.', + 'signup-account-free' => 'You are signing up for an account with 100% discount. You will be redirected immediately to your Dashboard.', 'signup-plan-monthly' => 'You are choosing a monthly subscription.', 'signup-plan-yearly' => 'You are choosing a yearly subscription.', 'signup-subscription-monthly' => 'Monthly subscription', diff --git a/src/resources/vue/Signup.vue b/src/resources/vue/Signup.vue --- a/src/resources/vue/Signup.vue +++ b/src/resources/vue/Signup.vue @@ -102,7 +102,7 @@
-
+

{{ $t('signup.created') }}

@@ -124,6 +124,16 @@
+
+

{{ $t('signup.created') }}

+
+

{{ checkout.content }}

+
+ {{ $t('btn.back') }} + {{ $t('btn.subscribe') }} +
+
+
@@ -340,11 +350,11 @@ const post = this.lastStepPostData() axios.post('/api/auth/signup', post).then(response => { - // auto-login and goto to the payment checkout - this.$root.loginUser(response.data, false) - let checkout = response.data.checkout + // auto-login and goto to the payment checkout (or Dashboard for a free account) + this.$root.loginUser(response.data, !checkout.id && !checkout.redirectUrl) + if (checkout.redirectUrl) { location.href = checkout.redirectUrl } else if (checkout.id) { diff --git a/src/tests/Browser/SignupTest.php b/src/tests/Browser/SignupTest.php --- a/src/tests/Browser/SignupTest.php +++ b/src/tests/Browser/SignupTest.php @@ -46,6 +46,7 @@ SignupInvitation::truncate(); Plan::whereNot('mode', Plan::MODE_EMAIL)->update(['mode' => Plan::MODE_EMAIL]); + Discount::where('discount', 100)->update(['code' => null]); @unlink(storage_path('signup-tokens.txt')); @@ -563,9 +564,9 @@ $browser->assertSeeIn('h4', 'The account is about to be created!') ->assertSeeIn('h5', 'You are choosing a monthly subscription') ->assertVisible('#summary-content') - ->assertElementsCount('#summary-cc svg', 2) - ->assertElementsCount('#summary-summary tr', 4) - ->assertSeeIn('button.btn-primary', 'Continue') + ->assertElementsCount('#summary-content + p.credit-cards img', 2) + ->assertVisible('#summary-summary') + ->assertSeeIn('button.btn-primary', 'Subscribe') ->assertSeeIn('button.btn-secondary', 'Back') ->click('button.btn-secondary'); }) @@ -616,6 +617,57 @@ } /** + * Test signup with a mandate plan with a discount=100% + */ + public function testSignupMandateDiscount100Percent(): void + { + // Test the individual plan + $plan = Plan::withEnvTenantContext()->where('title', 'individual')->first(); + $plan->mode = Plan::MODE_MANDATE; + $plan->save(); + + $discount = Discount::where('discount', 100)->first(); + $discount->code = 'FREE'; + $discount->save(); + + $this->browse(function (Browser $browser) { + $browser->visit(new Signup()) + ->waitFor('@step0 .plan-individual button') + ->click('@step0 .plan-individual button') + ->whenAvailable('@step0', function ($browser) { + $browser->click('.plan-individual button'); + }) + ->whenAvailable('@step3', function ($browser) { + $browser->type('#signup_login', 'signuptestdusk') + ->type('#signup_password', '12345678') + ->type('#signup_password_confirmation', '12345678') + ->type('#signup_voucher', 'FREE') + ->click('[type=submit]'); + }) + ->whenAvailable('@step4', function ($browser) { + $browser->assertSeeIn('h4', 'The account is about to be created!') + ->assertSeeIn('#summary-content', 'You are signing up for an account with 100% discount.') + ->assertMissing('#summary-summary') + ->assertSeeIn('button.btn-primary', 'Subscribe') + ->assertSeeIn('button.btn-secondary', 'Back') + ->click('button.btn-primary'); + }) + ->waitUntilMissing('@step4') + ->on(new Dashboard()) + ->within(new Menu(), function ($browser) { + $browser->clickMenuItem('logout'); + }); + }); + + $user = User::where('email', 'signuptestdusk@' . \config('app.domain'))->first(); + + $this->assertSame($plan->id, $user->getSetting('plan_id')); + $this->assertTrue($user->isActive()); + $this->assertFalse($user->isRestricted()); + $this->assertSame($discount->id, $user->wallets->first()->discount_id); + } + + /** * Test signup with a token plan */ public function testSignupToken(): void diff --git a/src/tests/Feature/Controller/SignupTest.php b/src/tests/Feature/Controller/SignupTest.php --- a/src/tests/Feature/Controller/SignupTest.php +++ b/src/tests/Feature/Controller/SignupTest.php @@ -977,7 +977,7 @@ VatRate::create([ 'country' => 'CH', 'rate' => 7.7, - 'start' => now()->subSecond(), + 'start' => now()->copy()->subDay(), ]); IP4Net::create([