def cancel_subscription(uid: str, sub_id: str) -> FlaskResponse: """ Cancel an existing subscription for a user. :param uid: :param sub_id: :return: Success or failure message for the cancellation. """ customer = fetch_customer(g.subhub_account, uid) if not customer: return dict(message="Customer does not exist."), 404 for item in customer["subscriptions"]["data"]: if item["id"] == sub_id and item["status"] in [ "active", "trialing", "incomplete", ]: vendor.cancel_stripe_subscription_period_end( sub_id, utils.get_indempotency_key()) updated_customer = fetch_customer(g.subhub_account, uid) logger.info("updated customer", updated_customer=updated_customer) subs = retrieve_stripe_subscriptions(updated_customer) logger.info("subs", subs=subs, type=type(subs)) for sub in subs: if sub["cancel_at_period_end"] and sub["id"] == sub_id: return { "message": "Subscription cancellation successful" }, 201 return dict(message="Subscription not available."), 400
def subscribe_to_plan(uid: str, data: Dict[str, Any]) -> FlaskResponse: """ Subscribe to a plan given a user id, payment token, email, orig_system :param uid: :param data: :return: current subscriptions for user. """ customer = existing_or_new_customer( g.subhub_account, user_id=uid, email=data["email"], source_token=data["pmt_token"], origin_system=data["origin_system"], display_name=data["display_name"], ) existing_plan = has_existing_plan(customer, plan_id=data["plan_id"]) if existing_plan: return dict(message="User already subscribed."), 409 if not customer.get("deleted"): vendor.build_stripe_subscription(customer.id, data["plan_id"], utils.get_indempotency_key()) updated_customer = fetch_customer(g.subhub_account, user_id=uid) newest_subscription = find_newest_subscription( updated_customer["subscriptions"]) return create_return_data(newest_subscription), 201 return dict(message=None), 400
def customer_update(uid) -> tuple: """ Provide latest data for a given user :param uid: :return: return_data dict with credit card info and subscriptions """ customer = fetch_customer(g.subhub_account, uid) if not customer: response_message = dict(message="Customer does not exist.") logger.debug("customer update", response_message=response_message, response_code=404) return response_message, 404 metadata = customer.get("metadata", None) if metadata: if metadata.get("userid", None) == uid: return_data = create_update_data(customer) logger.debug("customer update", response_message=return_data, response_code=200) return return_data, 200 response_message = dict(message="Customer mismatch.") logger.debug("customer update", response_message=response_message, response_code=400) return response_message, 400
def test_fetch_customer_success(self): self.retrieve_stripe_customer_mock.return_value = self.customer1 subhub_account = self.subhub_account_mock("table", "region") subhub_account.get_user.return_value = self.subhub_user customer = fetch_customer(subhub_account, "user_1") assert customer == self.customer1
def test_fetch_customer_no_account(monkeypatch): """ GIVEN an invalid user_id WHEN a user attempts to fetch a customer THEN None is returned """ subhub_account = MagicMock() get_user = MagicMock(return_value=None) subhub_account.get_user = get_user customer = fetch_customer(subhub_account, "user123") assert customer is None
def customer_update(uid) -> tuple: """ Provide latest data for a given user :param uid: :return: return_data dict with credit card info and subscriptions """ try: customer = fetch_customer(g.subhub_account, uid) if not customer: return dict(message="Customer does not exist."), 404 if customer["metadata"]["userid"] == uid: return_data = create_update_data(customer) return return_data, 200 return dict(message="Customer mismatch."), 400 except KeyError as e: logger.error("Customer does not exist", error=e) return dict(message=f"Customer does not exist: missing {e}"), 404
def reactivate_subscription(uid: str, sub_id: str) -> FlaskResponse: """ Given a user's subscription that is flagged for cancellation, but is still active remove the cancellation flag to ensure the subscription remains active :param uid: User ID :param sub_id: Subscription ID :return: Success or failure message for the activation """ customer = fetch_customer(g.subhub_account, uid) if not customer: response_message = dict(message="Customer does not exist.") logger.debug("reactivate subscription", response_message=response_message) return response_message, 404 active_subscriptions = customer["subscriptions"]["data"] response_message = dict(message="Current subscription not found.") for subscription in active_subscriptions: if subscription["id"] == sub_id: response_message = dict(message="Subscription is already active.") if subscription["cancel_at_period_end"]: reactivate_stripe_subscription(sub_id, utils.get_indempotency_key()) response_message = dict( message="Subscription reactivation was successful.") logger.debug( "reactivate subscription", response_message=response_message, response_code=200, ) return response_message, 200 logger.debug( "reactivate subscription", response_message=response_message, response_code=200, ) return response_message, 200 logger.debug("reactivate subscription", response_message=response_message, response_code=404) return response_message, 404
def update_payment_method(uid, data) -> FlaskResponse: """ Given a user id and a payment token, update user's payment method :param uid: :param data: :return: Success or failure message. """ customer = fetch_customer(g.subhub_account, uid) logger.info("customer", customer=customer) if not customer: return dict(message="Customer does not exist."), 404 metadata = customer.get("metadata") logger.info("metadata", metadata=metadata, customer=type(customer)) if metadata: if metadata["userid"] == uid: Customer.modify(customer.id, source=data["pmt_token"]) return {"message": "Payment method updated successfully."}, 201 return dict(message="Customer mismatch."), 400
def update_payment_method(uid, data) -> FlaskResponse: """ Given a user id and a payment token, update user's payment method :param uid: :param data: :return: Success or failure message. """ customer = fetch_customer(g.subhub_account, uid) logger.debug("customer", customer=customer) if not customer: response_message = dict(message="Customer does not exist.") logger.debug( "update payment method", response_message=response_message, response_code=404, ) return response_message, 404 metadata = customer.get("metadata") logger.debug("metadata", metadata=metadata, customer=type(customer)) if metadata: if metadata.get("userid", None) == uid: modify_customer( customer_id=customer.id, source_token=data["pmt_token"], idempotency_key=utils.get_indempotency_key(), ) response_message = dict( message="Payment method updated successfully.") logger.debug( "update payment method", response_message=response_message, response_code=201, ) return response_message, 201 response_message = dict(message="Customer mismatch.") logger.debug("update payment method", response_message=response_message, response_code=400) return response_message, 400
def reactivate_subscription(uid: str, sub_id: str) -> FlaskResponse: """ Given a user's subscription that is flagged for cancellation, but is still active remove the cancellation flag to ensure the subscription remains active :param uid: User ID :param sub_id: Subscription ID :return: Success or failure message for the activation """ customer = fetch_customer(g.subhub_account, uid) if not customer: return dict(message="Customer does not exist."), 404 active_subscriptions = customer["subscriptions"]["data"] for subscription in active_subscriptions: if subscription["id"] == sub_id: if subscription["cancel_at_period_end"]: Subscription.modify(sub_id, cancel_at_period_end=False) return dict(message="Subscription reactivation was successful."), 200 return dict(message="Subscription is already active."), 200 return dict(message="Current subscription not found."), 404
def test_fetch_customer_success(monkeypatch): """ GIVEN a valid user_id that maps to a valid customer account WHEN a user attempts to fetch a customer THEN that customer is returned """ subhub_account = MagicMock() get_user = MagicMock() user_id = PropertyMock(return_value="user123") cust_id = PropertyMock(return_value="cust123") type(get_user).user_id = user_id type(get_user).cust_id = cust_id subhub_account.get_user = get_user mock_customer = MagicMock(return_value={"id": "cust123", "deleted": False}) monkeypatch.setattr("stripe.Customer.retrieve", mock_customer) customer = fetch_customer(subhub_account, "user123") assert customer is not None
def test_fetch_customer_failure(self): subhub_account = self.subhub_account_mock("table", "region") subhub_account.get_user.return_value = None customer = fetch_customer(subhub_account, "user_1") assert customer is None