From 56257c4b1b61f46ef0a594f2b78e8db21daacac4 Mon Sep 17 00:00:00 2001
From: Nicolas Dular <ndular@gitlab.com>
Date: Tue, 7 Jun 2022 14:47:53 +0200
Subject: [PATCH] Count awaiting users on checkout free groups

This changes how we calculate the billable members for free plans on the
`free_user_cap` when they purchase a plan.

Example: A free group where `free_user_cap` is enabled has 7 users.
2 users get their memberships set to `awaiting` when `free_user_cap`
applies. When they want to purchase a plan it's likely that they want to
purchase seats for these 2 users. We therefore need to count them in the
checkout process as `billable` members.

We also have to change the way how we calculate `seats_in_use` as it was
using `billable_members_count`. It's now using directly
`billed_user_ids` and we therefore distinguish between billable
(potentially billable) and billed users (actually billed users).
---
 ee/app/models/ee/group.rb                  |  6 +++++-
 ee/app/models/gitlab_subscription.rb       |  2 +-
 ee/spec/models/ee/group_spec.rb            | 22 ++++++++++++++++++++++
 ee/spec/models/gitlab_subscription_spec.rb | 16 ++++++++++++++++
 4 files changed, 44 insertions(+), 2 deletions(-)

diff --git a/ee/app/models/ee/group.rb b/ee/app/models/ee/group.rb
index 40111acb180e..81d4b5995ce0 100644
--- a/ee/app/models/ee/group.rb
+++ b/ee/app/models/ee/group.rb
@@ -397,7 +397,11 @@ def billable_members_count_with_reactive_cache
     def billable_members_count(requested_hosted_plan = nil)
       billable_ids = billed_user_ids(requested_hosted_plan)
 
-      billable_ids[:user_ids].count
+      if ::Namespaces::FreeUserCap.enforce_preview_or_standard?(self)
+        billable_ids[:user_ids].merge(awaiting_user_ids).count
+      else
+        billable_ids[:user_ids].count
+      end
     end
 
     override :free_plan_members_count
diff --git a/ee/app/models/gitlab_subscription.rb b/ee/app/models/gitlab_subscription.rb
index 7cec39d93901..ac4fe746e514 100644
--- a/ee/app/models/gitlab_subscription.rb
+++ b/ee/app/models/gitlab_subscription.rb
@@ -61,7 +61,7 @@ def legacy?
   end
 
   def calculate_seats_in_use
-    namespace.billable_members_count
+    namespace.billed_user_ids[:user_ids].count
   end
 
   # The purpose of max_seats_used is similar to what we do for EE licenses
diff --git a/ee/spec/models/ee/group_spec.rb b/ee/spec/models/ee/group_spec.rb
index 6e101e3df2db..6c9041324ff7 100644
--- a/ee/spec/models/ee/group_spec.rb
+++ b/ee/spec/models/ee/group_spec.rb
@@ -1495,6 +1495,28 @@
         end
       end
     end
+
+    context 'for free group' do
+      before do
+        allow(::Namespaces::FreeUserCap).to receive(:enforce_preview_or_standard?).with(group).and_return(free_user_cap_enabled)
+      end
+
+      context 'when free_user_cap is enabled' do
+        let(:free_user_cap_enabled) { true }
+
+        it 'includes awaiting members' do
+          expect(group.billable_members_count).to eq(3)
+        end
+      end
+
+      context 'when free_user_cap is disabled' do
+        let(:free_user_cap_enabled) { false }
+
+        it 'does not include awaiting members' do
+          expect(group.billable_members_count).to eq(2)
+        end
+      end
+    end
   end
 
   describe '#exclude_guests?', :saas do
diff --git a/ee/spec/models/gitlab_subscription_spec.rb b/ee/spec/models/gitlab_subscription_spec.rb
index 7b77e9029fe8..32f61a4c9624 100644
--- a/ee/spec/models/gitlab_subscription_spec.rb
+++ b/ee/spec/models/gitlab_subscription_spec.rb
@@ -88,6 +88,22 @@
       expect(gitlab_subscription.calculate_seats_in_use).to eq(1)
     end
 
+    context 'with free_user_cap' do
+      before do
+        group.add_developer(user_1)
+        group.add_developer(user_2)
+        create(:group_member, :awaiting, source: group)
+
+        gitlab_subscription.update!(plan_code: 'free')
+        stub_ee_application_setting(should_check_namespace_plan: true)
+      end
+
+      it 'does not count awaiting members' do
+        expect(group.member_count).to eq(3)
+        expect(gitlab_subscription.calculate_seats_in_use).to eq(2)
+      end
+    end
+
     context 'with guest members' do
       before do
         group.add_guest(user_1)
-- 
GitLab