Exemple #1
0
def get_subscription_info(request: AuthedHttpRequest,
                          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"})
Exemple #2
0
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
Exemple #3
0
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
Exemple #4
0
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,
    }
Exemple #5
0
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
Exemple #6
0
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(
        "web_api.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)
Exemple #7
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 = 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
Exemple #8
0
def usage_billing(request: AuthedHttpRequest, 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,
            )
        plan_interval = ("year" if stripe_customer_info.plan_interval == "year"
                         else "month")
        brand_title = (stripe_customer_info.payment_method_card_brand.title()
                       if stripe_customer_info.payment_method_card_brand
                       is not None else None)
        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,
                planInterval=plan_interval,
            ),
            billingEmail=stripe_customer_info.customer_email,
            contactEmails=account.contact_emails,
            customerName=stripe_customer_info.customer_name,
            customerAddress=customer_address,
            cardInfo=
            f"{brand_title} ({stripe_customer_info.payment_method_card_last4})",
            viewerIsOrgOwner=request.user.is_admin(account),
            viewerCanModify=request.user.can_edit_subscription(account),
            limitBillingAccessToOwners=account.limit_billing_access_to_owners,
        )

    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
    ]
    subscription_exemption = None

    if account.subscription_exempt:
        subscription_exemption = dict(
            message=account.subscription_exempt_message)

    return JsonResponse(
        dict(
            accountCanSubscribe=account.can_subscribe(),
            subscription=subscription,
            trial=trial,
            activeUsers=active_user_with_license_info,
            subscriptionExemption=subscription_exemption,
        ))
 def handle(self, *args: object, **options: object) -> None:
     UserPullRequestActivity.generate()
def main() -> None:
    UserPullRequestActivity.generate()
Exemple #11
0
 def handle(self, *args, **options):
     UserPullRequestActivity.generate()