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'] = '
';
+ $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') }}
+
+
{{ $t('signup.created') }}
+
+
{{ checkout.content }}
+
+
+
@@ -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([