Exemplo n.º 1
0
def advantage_payment_methods_view(**kwargs):
    is_test_backend = kwargs.get("test_backend")
    stripe_publishable_key = kwargs["stripe_publishable_key"]
    api_url = kwargs.get("api_url")
    token = kwargs.get("token")

    advantage = UAContractsAPI(session,
                               token,
                               api_url=api_url,
                               is_for_view=True)

    try:
        account = advantage.get_purchase_account()
    except UAContractsUserHasNoAccount as error:
        raise UAContractsAPIErrorView(error)

    account_info = advantage.get_customer_info(account["id"])
    customer_info = account_info["customerInfo"]
    default_payment_method = customer_info.get("defaultPaymentMethod")

    return flask.render_template(
        "advantage/payment-methods/index.html",
        stripe_publishable_key=stripe_publishable_key,
        is_test_backend=is_test_backend,
        default_payment_method=default_payment_method,
        account_id=account["id"],
    )
Exemplo n.º 2
0
def accept_renewal(renewal_id, **kwargs):
    token = kwargs.get("token")
    api_url = kwargs.get("api_url")

    advantage = UAContractsAPI(session, token, api_url=api_url)

    return advantage.accept_renewal(renewal_id)
Exemplo n.º 3
0
def post_payment_method(**kwargs):
    api_url = kwargs.get("api_url")
    token = kwargs.get("token")
    account_id = kwargs.get("account_id")
    payment_method_id = kwargs.get("payment_method_id")

    advantage = UAContractsAPI(session, token, api_url=api_url)

    return advantage.put_payment_method(account_id, payment_method_id)
Exemplo n.º 4
0
def get_purchase(purchase_id, **kwargs):
    api_url = kwargs.get("api_url")
    token = kwargs.get("token")
    token_type = kwargs.get("token_type")

    advantage = UAContractsAPI(
        session, token, token_type=token_type, api_url=api_url
    )

    return advantage.get_purchase(purchase_id)
Exemplo n.º 5
0
def post_stripe_invoice_id(tx_type, tx_id, invoice_id, **kwargs):
    api_url = kwargs.get("api_url")
    token = kwargs.get("token")
    token_type = kwargs.get("token_type")

    advantage = UAContractsAPI(session,
                               token,
                               token_type=token_type,
                               api_url=api_url)

    return advantage.post_stripe_invoice_id(tx_type, tx_id, invoice_id)
Exemplo n.º 6
0
def post_anonymised_customer_info(**kwargs):
    api_url = kwargs.get("api_url")
    token = kwargs.get("token")
    token_type = kwargs.get("token_type")
    account_id = kwargs.get("account_id")
    address = kwargs.get("address")
    tax_id = kwargs.get("tax_id")

    advantage = UAContractsAPI(session,
                               token,
                               token_type=token_type,
                               api_url=api_url)

    return advantage.put_anonymous_customer_info(account_id, address, tax_id)
Exemplo n.º 7
0
def post_stripe_invoice_id(tx_type, tx_id, invoice_id, **kwargs):
    api_url = kwargs.get("api_url")
    token = kwargs.get("token")
    token_type = kwargs.get("token_type")

    advantage = UAContractsAPI(
        session, token, token_type=token_type, api_url=api_url
    )

    response = advantage.post_stripe_invoice_id(tx_type, tx_id, invoice_id)

    if response is None:
        return flask.jsonify({"message": "invoice updated"})

    return response
Exemplo n.º 8
0
def post_customer_info(**kwargs):
    api_url = kwargs.get("api_url")
    token = kwargs.get("token")
    token_type = kwargs.get("token_type")
    payment_method_id = kwargs.get("payment_method_id")
    account_id = kwargs.get("account_id")
    address = kwargs.get("address")
    name = kwargs.get("name")
    tax_id = kwargs.get("tax_id")

    advantage = UAContractsAPI(
        session, token, token_type=token_type, api_url=api_url
    )

    return advantage.put_customer_info(
        account_id, payment_method_id, address, name, tax_id
    )
Exemplo n.º 9
0
def make_client(session: Session, **kwargs):
    """Create and return a ua-contracts client for tests."""
    return UAContractsAPI(
        session,
        "secret-token",
        token_type="Bearer",
        api_url="https://1.2.3.4/contracts/",
        **kwargs,
    )
Exemplo n.º 10
0
def get_customer_info(account_id, **kwargs):
    api_url = kwargs.get("api_url")
    token = kwargs.get("token")

    response = {"success": False, "data": {}}

    try:
        advantage = UAContractsAPI(session, token, api_url=api_url)
        response["data"] = advantage.get_customer_info(account_id)
        response["success"] = True
    except HTTPError as error:
        if error.response.status_code == 404:
            response["data"] = error.response.json()
            response["success"] = False
        else:
            flask.current_app.extensions["sentry"].captureException()
            raise error

    return response
Exemplo n.º 11
0
def ensure_purchase_account(**kwargs):
    """
    Returns an object with the ID of an account a user can make
    purchases on. If the user is not logged in, the object also
    contains an auth token required for subsequent calls to the
    contract API.
    """

    api_url = kwargs.get("api_url")
    email = kwargs.get("email")
    account_name = kwargs.get("account_name")
    payment_method_id = kwargs.get("payment_method_id")
    country = kwargs.get("country")

    token = None
    if user_info(flask.session):
        token = flask.session["authentication_token"]

    advantage = UAContractsAPI(session, token, api_url=api_url)

    try:
        account = advantage.ensure_purchase_account(
            email=email,
            account_name=account_name,
            payment_method_id=payment_method_id,
            country=country,
        )
    except UnauthorizedError as err:
        # This kind of errors are handled js side.
        return err.asdict(), 200
    except HTTPError as err:
        flask.current_app.extensions["sentry"].captureException()
        return err.response.content, 500

    # The guest authentication token is included in the response only when the
    # user is not logged in.
    token = account.get("token")

    if token:
        flask.session["guest_authentication_token"] = token

    return flask.jsonify(account), 200
Exemplo n.º 12
0
def post_auto_renewal_settings(**kwargs):
    api_url = kwargs.get("api_url")
    token = kwargs.get("token")
    should_auto_renew = kwargs.get("should_auto_renew", False)

    advantage = UAContractsAPI(session, token, api_url=api_url)
    accounts = advantage.get_accounts()

    for account in accounts:
        monthly_subscriptions = advantage.get_account_subscriptions(
            account_id=account["id"],
            marketplace="canonical-ua",
            filters={"status": "active", "period": "monthly"},
        )

        for subscription in monthly_subscriptions:
            advantage.post_subscription_auto_renewal(
                subscription_id=subscription["subscription"]["id"],
                should_auto_renew=should_auto_renew,
            )

    return (
        flask.jsonify({"message": "subscription renewal status was changed"}),
        200,
    )
Exemplo n.º 13
0
def advantage_payment_methods_view(**kwargs):
    is_test_backend = kwargs.get("test_backend")
    stripe_publishable_key = kwargs["stripe_publishable_key"]
    api_url = kwargs.get("api_url")
    token = kwargs.get("token")

    advantage = UAContractsAPI(session,
                               token,
                               api_url=api_url,
                               is_for_view=True)

    try:
        account = advantage.get_purchase_account()
    except UAContractsUserHasNoAccount as error:
        raise UAContractsAPIErrorView(error)

    subscriptions = advantage.get_account_subscriptions(
        account_id=account["id"],
        marketplace="canonical-ua",
        filters={"status": "locked"},
    )

    pending_purchase_id = ""
    for subscription in subscriptions:
        if subscription.get("pendingPurchases"):
            pending_purchase_id = subscription.get("pendingPurchases")[0]
            break

    account_info = advantage.get_customer_info(account["id"])
    customer_info = account_info["customerInfo"]
    default_payment_method = customer_info.get("defaultPaymentMethod")

    return flask.render_template(
        "advantage/payment-methods/index.html",
        stripe_publishable_key=stripe_publishable_key,
        is_test_backend=is_test_backend,
        default_payment_method=default_payment_method,
        pending_purchase_id=pending_purchase_id,
        account_id=account["id"],
    )
Exemplo n.º 14
0
def cancel_advantage_subscriptions(**kwargs):
    api_url = kwargs.get("api_url")
    token = kwargs.get("token")
    account_id = kwargs.get("account_id")
    previous_purchase_id = kwargs.get("previous_purchase_id")
    product_listing_id = kwargs.get("product_listing_id")

    advantage = UAContractsAPI(session, token, api_url=api_url)

    monthly_subscriptions = advantage.get_account_subscriptions(
        account_id=account_id,
        marketplace="canonical-ua",
        filters={
            "status": "active",
            "period": "monthly"
        },
    )

    if not monthly_subscriptions:
        return flask.jsonify({"error": "no monthly subscriptions found"}), 400

    monthly_subscription = monthly_subscriptions[0]

    purchase_request = {
        "accountID":
        account_id,
        "purchaseItems": [{
            "productListingID": product_listing_id,
            "metric": "active-machines",
            "value": 0,
            "delete": True,
        }],
        "previousPurchaseID":
        previous_purchase_id,
    }

    try:
        purchase = advantage.purchase_from_marketplace(
            marketplace="canonical-ua", purchase_request=purchase_request)
    except CannotCancelLastContractError:
        advantage.cancel_subscription(
            subscription_id=monthly_subscription["subscription"]["id"])

        return (
            flask.jsonify({"message": "Subscription Cancelled"}),
            200,
        )

    return flask.jsonify(purchase), 200
Exemplo n.º 15
0
def post_advantage_subscriptions(preview, **kwargs):
    api_url = kwargs.get("api_url")
    token = kwargs.get("token")
    token_type = kwargs.get("token_type")
    account_id = kwargs.get("account_id")
    previous_purchase_id = kwargs.get("previous_purchase_id")
    period = kwargs.get("period")
    products = kwargs.get("products")
    resizing = kwargs.get("resizing", False)

    advantage = UAContractsAPI(
        session, token, token_type=token_type, api_url=api_url
    )

    current_subscription = {}
    if user_info(flask.session):
        subscriptions = advantage.get_account_subscriptions(
            account_id=account_id,
            marketplace="canonical-ua",
            filters={"status": "active"},
        )

        for subscription in subscriptions:
            if subscription["subscription"]["period"] == period:
                current_subscription = subscription

    # If there is a subscription we get the current metric
    # value for each product listing so we can generate a
    # purchase request with updated quantities later.
    # If we resize we want to override the existing value
    subscribed_quantities = {}
    if not resizing and current_subscription:
        for item in current_subscription["purchasedProductListings"]:
            product_listing_id = item["productListing"]["id"]
            subscribed_quantities[product_listing_id] = item["value"]

    purchase_items = []
    for product in products:
        product_listing_id = product["product_listing_id"]
        metric_value = product["quantity"] + subscribed_quantities.get(
            product_listing_id, 0
        )

        purchase_items.append(
            {
                "productListingID": product_listing_id,
                "metric": "active-machines",
                "value": metric_value,
            }
        )

    purchase_request = {
        "accountID": account_id,
        "purchaseItems": purchase_items,
        "previousPurchaseID": previous_purchase_id,
    }

    try:
        if not preview:
            purchase = advantage.purchase_from_marketplace(
                marketplace="canonical-ua", purchase_request=purchase_request
            )
        else:
            purchase = advantage.preview_purchase_from_marketplace(
                marketplace="canonical-ua", purchase_request=purchase_request
            )
    except CannotCancelLastContractError as error:
        raise UAContractsAPIError(error)

    return flask.jsonify(purchase), 200
Exemplo n.º 16
0
def advantage_shop_view(**kwargs):
    is_test_backend = kwargs.get("test_backend")
    api_url = kwargs.get("api_url")
    stripe_publishable_key = kwargs.get("stripe_publishable_key")
    token = kwargs.get("token")

    account = None
    previous_purchase_ids = {"monthly": "", "yearly": ""}
    advantage = UAContractsAPI(
        session, None, api_url=api_url, is_for_view=True
    )

    if user_info(flask.session):
        advantage = UAContractsAPI(
            session, token, api_url=api_url, is_for_view=True
        )

        if flask.session.get("guest_authentication_token"):
            flask.session.pop("guest_authentication_token")

        try:
            account = advantage.get_purchase_account()
        except UAContractsUserHasNoAccount:
            # There is no purchase account yet for this user.
            # One will need to be created later, but this is an expected
            # condition.

            pass

        if account:
            subscriptions = advantage.get_account_subscriptions(
                account_id=account["id"],
                marketplace="canonical-ua",
                filters={"status": "active"},
            )

            for subscription in subscriptions:
                period = subscription["subscription"]["period"]
                previous_purchase_ids[period] = subscription["lastPurchaseID"]

    listings = advantage.get_product_listings("canonical-ua")
    product_listings = listings.get("productListings")
    if not product_listings:
        # For the time being, no product listings means the shop has not been
        # activated, so fallback to shopify. This should become an error later.
        return flask.redirect("https://buy.ubuntu.com/")

    products = {product["id"]: product for product in listings["products"]}

    website_listing = []
    for listing in product_listings:
        if "price" not in listing:
            continue

        listing["product"] = products[listing["productID"]]

        website_listing.append(listing)

    return flask.render_template(
        "advantage/subscribe/index.html",
        is_test_backend=is_test_backend,
        stripe_publishable_key=stripe_publishable_key,
        account=account,
        previous_purchase_ids=previous_purchase_ids,
        product_listings=website_listing,
    )
Exemplo n.º 17
0
def advantage_view(**kwargs):
    is_test_backend = kwargs.get("test_backend")
    api_url = kwargs.get("api_url")
    stripe_publishable_key = kwargs["stripe_publishable_key"]
    token = kwargs.get("token")
    open_subscription = kwargs.get("subscription", None)

    personal_account = None
    new_subscription_id = None
    new_subscription_start_date = None
    pending_purchase_id = None

    enterprise_contracts = {}
    previous_purchase_ids = {"monthly": "", "yearly": ""}
    total_enterprise_contracts = 0

    monthly_info = {
        "total_subscriptions": 0,
        "has_monthly": False,
        "next_payment": {},
    }

    advantage = UAContractsAPI(
        session, token, api_url=api_url, is_for_view=True
    )

    # Support admin "view as" functionality.
    email = kwargs.get("email", "").strip()
    accounts = advantage.get_accounts(email=email)

    for account in accounts:
        monthly_purchased_products = {}
        yearly_purchased_products = {}
        account["contracts"] = advantage.get_account_contracts(account["id"])

        all_subscriptions = advantage.get_account_subscriptions(
            account_id=account["id"],
            marketplace="canonical-ua",
        )

        monthly_subscriptions = []
        yearly_subscriptions = []
        for subscription in all_subscriptions:
            period = subscription["subscription"]["period"]
            status = subscription["subscription"]["status"]

            if status not in ["active", "locked"]:
                continue

            if subscription.get("pendingPurchases"):
                pending_purchase_id = subscription.get("pendingPurchases")[0]

            previous_purchase_ids[period] = subscription.get("lastPurchaseID")

            if subscription["subscription"]["period"] == "yearly":
                yearly_subscriptions.append(subscription)
                continue

            monthly_subscriptions.append(subscription)

        for subscription in monthly_subscriptions:
            purchased_products = subscription.get("purchasedProductListings")
            if purchased_products is None:
                continue

            for purchased_product_listing in purchased_products:
                product_listing = purchased_product_listing["productListing"]
                product_id = product_listing["productID"]
                quantity = purchased_product_listing["value"]
                monthly_purchased_products[product_id] = {
                    "quantity": quantity,
                    "price": product_listing["price"],
                    "product_listing_id": product_listing["id"],
                }

            _prepare_monthly_info(monthly_info, subscription, advantage)

        for subscription in yearly_subscriptions:
            purchased_products = subscription.get("purchasedProductListings")
            if purchased_products is None:
                continue

            for purchased_product_listing in purchased_products:
                product_listing = purchased_product_listing["productListing"]
                product_id = product_listing["productID"]
                quantity = purchased_product_listing["value"]
                yearly_purchased_products[product_id] = {
                    "quantity": quantity,
                    "price": product_listing["price"],
                    "product_listing_id": product_listing["id"],
                }

        for contract in account["contracts"]:
            contract_info = contract["contractInfo"]
            if not contract_info.get("items"):
                # TODO(frankban): clean up existing contracts with no items in
                # production.
                continue

            contract_id = contract_info["id"]
            contract["token"] = advantage.get_contract_token(contract_id)

            if contract_info.get("origin", "") == "free":
                personal_account = account
                personal_account["free_token"] = contract["token"]

                continue

            entitlements = {}
            for entitlement in contract_info["resourceEntitlements"]:
                contract["supportLevel"] = "-"
                if entitlement["type"] == "support":
                    affordance = entitlement["affordances"]
                    contract["supportLevel"] = affordance["supportLevel"]

                    continue

                entitlement_type = entitlement["type"]
                entitlements[entitlement_type] = True
            contract["entitlements"] = entitlements

            created_at = parse(contract_info["createdAt"])
            format_create = created_at.strftime("%d %B %Y")
            contract["contractInfo"]["createdAtFormatted"] = format_create
            contract["contractInfo"]["status"] = "active"

            time_now = datetime.utcnow().replace(tzinfo=pytz.utc)

            if (
                not new_subscription_start_date
                or created_at > new_subscription_start_date
            ):
                new_subscription_start_date = created_at
                new_subscription_id = contract["contractInfo"]["id"]

            effective_to = parse(contract_info["effectiveTo"])
            format_effective = effective_to.strftime("%d %B %Y")
            contract["contractInfo"]["effectiveToFormatted"] = format_effective

            if effective_to < time_now:
                contract["contractInfo"]["status"] = "expired"
                restart_date = time_now - timedelta(days=1)
                contract["contractInfo"]["expired_restart_date"] = restart_date

            date_difference = effective_to - time_now
            contract["expiring"] = date_difference.days <= 30
            contract["contractInfo"]["daysTillExpiry"] = date_difference.days

            try:
                contract["renewal"] = _make_renewal(
                    advantage, contract["contractInfo"]
                )
            except KeyError:
                flask.current_app.extensions["sentry"].captureException()
                contract["renewal"] = None

            enterprise_contract = enterprise_contracts.setdefault(
                contract["accountInfo"]["name"], []
            )

            product_name = contract["contractInfo"]["products"][0]

            contract["productID"] = product_name
            contract["is_detached"] = False
            contract["machineCount"] = 0
            contract["rowMachineCount"] = 0

            allowances = contract_info.get("allowances")
            if (
                allowances
                and len(allowances) > 0
                and allowances[0]["metric"] == "units"
            ):
                contract["rowMachineCount"] = allowances[0]["value"]

            if product_name in yearly_purchased_products:
                purchased_product = yearly_purchased_products[product_name]
                contract["price_per_unit"] = purchased_product["price"]
                contract["machineCount"] = purchased_product["quantity"]
                contract["product_listing_id"] = purchased_product[
                    "product_listing_id"
                ]
                contract["period"] = "yearly"

                if contract["contractInfo"]["id"] == open_subscription:
                    enterprise_contract.insert(0, contract)
                elif contract["contractInfo"]["id"] == new_subscription_id:
                    enterprise_contract.insert(0, contract)
                else:
                    enterprise_contract.append(contract)

                if contract["contractInfo"]["status"] != "expired":
                    total_enterprise_contracts += 1

            if product_name in monthly_purchased_products:
                contract = contract.copy()
                purchased_product = monthly_purchased_products[product_name]
                contract["price_per_unit"] = purchased_product["price"]
                contract["machineCount"] = purchased_product["quantity"]
                contract["is_cancelable"] = True
                contract["product_listing_id"] = purchased_product[
                    "product_listing_id"
                ]
                contract["period"] = "monthly"

                if contract["contractInfo"]["id"] == open_subscription:
                    enterprise_contract.insert(0, contract)
                elif contract["contractInfo"]["id"] == new_subscription_id:
                    enterprise_contract.insert(0, contract)
                else:
                    enterprise_contract.append(contract)

                if contract["contractInfo"]["status"] != "expired":
                    total_enterprise_contracts += 1

            if (
                product_name not in yearly_purchased_products
                and product_name not in monthly_purchased_products
            ):
                contract["is_detached"] = True

                if contract["contractInfo"]["id"] == open_subscription:
                    enterprise_contract.insert(0, contract)
                elif contract["contractInfo"]["id"] == new_subscription_id:
                    enterprise_contract.insert(0, contract)
                else:
                    enterprise_contract.append(contract)

                if contract["contractInfo"]["status"] != "expired":
                    total_enterprise_contracts += 1

    return flask.render_template(
        "advantage/index.html",
        accounts=accounts,
        monthly_information=monthly_info,
        total_enterprise_contracts=total_enterprise_contracts,
        pending_purchase_id=pending_purchase_id,
        enterprise_contracts=enterprise_contracts,
        previous_purchase_ids=previous_purchase_ids,
        personal_account=personal_account,
        open_subscription=open_subscription,
        new_subscription_id=new_subscription_id,
        stripe_publishable_key=stripe_publishable_key,
        is_test_backend=is_test_backend,
    )