def test_get_active_users_in_last_30_days() -> None: account = Account(github_installation_id=52324234) create_user_activity( account=account, user_id=333777, pr_number=953, date=timezone.now() - datetime.timedelta(days=5), ) create_user_activity( account=account, user_id=333777, pr_number=953, date=timezone.now() ) create_user_activity( account=account, user_id=90322322, pr_number=883, date=timezone.now() - datetime.timedelta(days=10), ) create_user_activity( account=account, user_id=90322322, pr_number=883, date=timezone.now() ) active_users = UserPullRequestActivity.get_active_users_in_last_30_days(account) assert len(active_users) == 2 assert active_users[0].github_id == 90322322 assert active_users[1].github_id == 333777
def get_subscription_info(request: HttpRequest, team_id: str) -> JsonResponse: account = get_account_or_404(team_id=team_id, user=request.user) subscription_status = account.get_subscription_blocker() if subscription_status is not None: if subscription_status.kind == "trial_expired": return JsonResponse({"type": "TRIAL_EXPIRED"}) if subscription_status.kind == "seats_exceeded": stripe_info = account.stripe_customer_info() license_count = 0 if stripe_info and stripe_info.subscription_quantity: license_count = stripe_info.subscription_quantity active_user_count: int = len( UserPullRequestActivity.get_active_users_in_last_30_days( account=account)) return JsonResponse({ "type": "SUBSCRIPTION_OVERAGE", "activeUserCount": active_user_count, "licenseCount": license_count, }) if subscription_status.kind == "subscription_expired": return JsonResponse({"type": "SUBSCRIPTION_EXPIRED"}) return JsonResponse({"type": "VALID_SUBSCRIPTION"})
def test_get_subscription_info_view_subscription_overage(mocker: MockFixture) -> None: """ check the API response when a user's account has exceeded the number of seats """ user, account = create_account() account.stripe_customer_id = create_stripe_customer_info().customer_id account.github_account_type = AccountType.organization account.save() for i in range(1, 6): create_active_user(account=account, user_id=i, pr_number=i) assert account.github_account_type != AccountType.user assert account.active_trial() is False stripe_customer_info = account.stripe_customer_info() assert stripe_customer_info is not None assert stripe_customer_info.subscription_quantity < len( UserPullRequestActivity.get_active_users_in_last_30_days(account=account) ) client = Client() client.login(user) res = client.get(f"/v1/t/{account.id}/subscription_info") assert res.status_code == 200 assert res.json() == { "type": "SUBSCRIPTION_OVERAGE", "activeUserCount": 5, "licenseCount": 3, }
def test_get_subscription_blocker_seats_exceeded( patched_get_active_users_in_last_30_days: Any, ) -> None: account = create_account(trial_expiration=None) stripe_customer_information = StripeCustomerInformation.objects.create( customer_id="cus_H2pvQ2kt7nk0JY", subscription_id="sub_Gu1xedsfo1", plan_id="plan_G2df31A4G5JzQ", payment_method_id="pm_22dldxf3", customer_email="*****@*****.**", customer_balance=0, customer_created=1585781308, payment_method_card_brand="mastercard", payment_method_card_exp_month="03", payment_method_card_exp_year="32", payment_method_card_last4="4242", plan_amount=499, subscription_quantity=3, subscription_start_date=1585781784, # subscription_current_period_start=0, subscription_current_period_end=1987081359, ) assert stripe_customer_information.expired is False assert patched_get_active_users_in_last_30_days.call_count == 0 assert (len( UserPullRequestActivity.get_active_users_in_last_30_days( account=account)) == 5) assert patched_get_active_users_in_last_30_days.call_count == 1 blocker = account.get_subscription_blocker() assert blocker is not None assert blocker.kind == "seats_exceeded" assert patched_get_active_users_in_last_30_days.call_count == 2
def test_get_subscription_blocker_seats_exceeded_with_trial( patched_get_active_users_in_last_30_days: Any, ) -> None: """ If an account has active users but is on the trial we should allow them full access. """ account = create_account(trial_expiration=make_aware( datetime.datetime(2100, 2, 13)), ) assert account.active_trial() is True assert (len( UserPullRequestActivity.get_active_users_in_last_30_days( account=account)) == 5) assert account.get_subscription_blocker() is None
def test_get_subscription_blocker_seats_exceeded_no_sub_or_trial_no_activity( mocker: Any, ) -> None: """ If an account has no trial or subscription, but also no active users, we should not raise the paywall. """ mocker.patch( "core.models.UserPullRequestActivity.get_active_users_in_last_30_days", return_value=[], ) account = create_account(trial_expiration=None) assert account.get_subscription_blocker() is None assert (len( UserPullRequestActivity.get_active_users_in_last_30_days( account=account)) == 0)
def usage_billing(request: HttpRequest, team_id: str) -> HttpResponse: account = get_object_or_404( Account.objects.filter(memberships__user=request.user), id=team_id) active_users = UserPullRequestActivity.get_active_users_in_last_30_days( account) return JsonResponse( dict(activeUsers=[ dict( id=active_user.github_id, name=active_user.github_login, profileImgUrl=active_user.profile_image(), interactions=active_user.days_active, lastActiveDate=active_user.last_active_at.isoformat(), ) for active_user in active_users ], ))
def test_get_subscription_blocker_seats_exceeded_with_trial( patched_get_active_users_in_last_30_days: Any, ) -> None: """ If an account has active users but is on the trial we should allow them full access. """ account = Account.objects.create( github_installation_id=1066615, github_account_login="******", github_account_id=523412234, github_account_type="Organization", stripe_customer_id="cus_H2pvQ2kt7nk0JY", trial_expiration=make_aware(datetime.datetime(2100, 2, 13)), ) assert account.active_trial() is True assert (len( UserPullRequestActivity.get_active_users_in_last_30_days( account=account)) == 5) assert account.get_subscription_blocker() is None
def test_get_subscription_blocker_seats_exceeded_no_sub_or_trial( patched_get_active_users_in_last_30_days: Any, ) -> None: """ If an account has active users but no trial or subscription, that should trigger the paywall when the active user count has been exceeded. """ account = create_account(trial_expiration=None) assert account.github_account_type == AccountType.organization assert patched_get_active_users_in_last_30_days.call_count == 0 blocker = account.get_subscription_blocker() assert blocker is not None assert blocker.kind == "seats_exceeded" assert patched_get_active_users_in_last_30_days.call_count == 1 assert (len( UserPullRequestActivity.get_active_users_in_last_30_days( account=account)) == 5) account.github_account_type = AccountType.user account.save() assert account.get_subscription_blocker() is None
def test_get_subscription_blocker_seats_exceeded_no_sub_or_trial_no_activity( mocker: Any, ) -> None: """ If an account has no trial or subscription, but also no active users, we should not raise the paywall. """ mocker.patch( "core.models.UserPullRequestActivity.get_active_users_in_last_30_days", return_value=[], ) account = Account.objects.create( github_installation_id=1066615, github_account_login="******", github_account_id=523412234, github_account_type="Organization", stripe_customer_id="cus_H2pvQ2kt7nk0JY", ) assert account.get_subscription_blocker() is None assert (len( UserPullRequestActivity.get_active_users_in_last_30_days( account=account)) == 0)
def test_get_subscription_blocker_seats_exceeded_no_sub_or_trial( patched_get_active_users_in_last_30_days: Any, ) -> None: """ If an account has active users but no trial or subscription, that should trigger the paywall when the active user count has been exceeded. """ account = Account.objects.create( github_installation_id=1066615, github_account_login="******", github_account_id=523412234, github_account_type="Organization", stripe_customer_id="cus_H2pvQ2kt7nk0JY", ) assert account.github_account_type == AccountType.organization assert patched_get_active_users_in_last_30_days.call_count == 0 assert account.get_subscription_blocker().kind == "seats_exceeded" assert patched_get_active_users_in_last_30_days.call_count == 1 assert (len( UserPullRequestActivity.get_active_users_in_last_30_days( account=account)) == 5) account.github_account_type = AccountType.user account.save() assert account.get_subscription_blocker() is None
def usage_billing(request: HttpRequest, team_id: str) -> HttpResponse: account = get_account_or_404(user=request.user, team_id=team_id) active_users = UserPullRequestActivity.get_active_users_in_last_30_days( account) subscription = None trial = None if account.trial_start and account.trial_expiration and account.trial_started_by: trial = dict( startDate=account.trial_start, endDate=account.trial_expiration, expired=account.trial_expired(), startedBy=dict( id=account.trial_started_by.id, name=account.trial_started_by.github_login, profileImgUrl=account.trial_started_by.profile_image(), ), ) stripe_customer_info = account.stripe_customer_info() if stripe_customer_info: customer_address = None if stripe_customer_info.customer_address_line1 is not None: customer_address = dict( line1=stripe_customer_info.customer_address_line1, city=stripe_customer_info.customer_address_city, country=stripe_customer_info.customer_address_country, line2=stripe_customer_info.customer_address_line2, postalCode=stripe_customer_info.customer_address_postal_code, state=stripe_customer_info.customer_address_state, ) subscription = dict( seats=stripe_customer_info.subscription_quantity, nextBillingDate=stripe_customer_info.next_billing_date, expired=stripe_customer_info.expired, cost=dict( totalCents=stripe_customer_info.plan_amount * stripe_customer_info.subscription_quantity, perSeatCents=stripe_customer_info.plan_amount, currency=stripe_customer_info.customer_currency or DEFAULT_CURRENCY, ), billingEmail=stripe_customer_info.customer_email, customerName=stripe_customer_info.customer_name, customerAddress=customer_address, cardInfo= f"{stripe_customer_info.payment_method_card_brand.title()} ({stripe_customer_info.payment_method_card_last4})", ) subscription_quantity = (stripe_customer_info.subscription_quantity if stripe_customer_info else 0) # we assign seats to users in order of first active for the last 30 days. allowed_user_ids = { user.github_id for user in sorted(active_users, key=lambda x: x.first_active_at) [:subscription_quantity] } active_user_with_license_info = [ dict( id=active_user.github_id, name=active_user.github_login, profileImgUrl=active_user.profile_image(), interactions=active_user.days_active, lastActiveDate=active_user.last_active_at.isoformat(), firstActiveDate=active_user.first_active_at.isoformat(), hasSeatLicense=(active_user.github_id in allowed_user_ids), ) for active_user in active_users ] return JsonResponse( dict( accountCanSubscribe=account.github_account_type != AccountType.user, subscription=subscription, trial=trial, activeUsers=active_user_with_license_info, ))
def handle(self, *args, **options): UserPullRequestActivity.generate()
def main() -> None: UserPullRequestActivity.generate()