Пример #1
0
    def delete_stripe_customer(self) -> bool:
        if self.user.plan != Plan.free():
            self.user.plan = Plan.free()
            self.unlink_from_plan(self.user.plan)

        stripe.Customer.delete(self.user.stripe_id)

        self.user.stripe_id = None
        self.user.stripe_payment_method = None

        return True
Пример #2
0
    def link_to_plan(self, plan: Plan) -> None:
        uns = UserNotification(self.user)
        subscription: stripe.Subscription = None

        # this is an unrecoverable situation - we will need to set
        # up the users stripe id before this point - they should
        # not be able to get here without it.
        assert self.user.stripe_id is not None

        subscription = stripe.Subscription.create(
            customer=self.user.stripe_id,
            default_payment_method=self.user.stripe_payment_method,
            items=[{"plan": plan.stripe_id}],
            expand=["latest_invoice.payment_intent"],
        )

        if subscription.latest_invoice.payment_intent.status == "succeeded":
            uns.subscribed_successfully()
            return

        if subscription.latest_invoice.payment_intent.status == "requires_action":
            uns.subscription_requires_action()
        else:
            uns.subscribed_failed()

        self.user.plan = Plan.free()
Пример #3
0
 def test_user_unsubscribed_is_run_when_user_tier_is_changed_to_free(
         self, user_unsubscribed, session):
     user = UserFactory()
     user.plan = Plan.free()
     session.add(user)
     session.commit()
     user_unsubscribed.assert_called_with(user.id)
    def test_user_unlink_from_plan_via_subscription(self):
        """Unlink a User from a plan based on change in their stripe subscription"""
        user = StripedUserFactory(tier="paid",
                                  stripe__payment_method="pm_card_visa")
        subscription = UserStripe(user)._retrieve_users_subscriptions(
            Plan.paid())

        UserStripe(user).unlink_from_plan_via_subscription(subscription.id)

        assert UserStripe(user)._retrieve_users_subscriptions(
            Plan.paid()) is None
        assert user.plan == Plan.free()
    def test_user_unsubscribed(self, unsubscribe_successful,
                               unsubscribe_not_required, session):
        """ User unsubscribes successfully """
        user = SubscribedUserFactory(tier="paid",
                                     stripe__payment_method="pm_card_visa")
        user.plan = Plan.free()
        session.add(user)
        session.flush()

        UserStripe(user).unlink_from_plan(Plan.paid())

        assert unsubscribe_successful.called_once
        assert not unsubscribe_not_required.called
Пример #6
0
    def test_user_unsubscribed_is_run_when_user_tier_is_changed_to_free(
        self, user_unsubscribed, session
    ):
        user = UserFactory()
        db.session.add(user)
        db.session.flush()

        UserUpdate(
            user=user,
            rels={"plan": {"data": {"type": "plan", "id": str(Plan.free().id)}}},
        ).update()

        db.session.commit()

        user_unsubscribed.assert_called_with(user.id, Plan.paid().id)
    def test_user_unsubscribed_but_didnt_need_to(self, unsubscribe_successful,
                                                 unsubscribe_not_required,
                                                 session):
        """User can't unsubscribe if they're not subscribed in the first place
        <taps forehead>"""

        user = StripedUserFactory(tier="free",
                                  stripe__payment_method="pm_card_visa")
        user.plan = Plan.free()
        session.add(user)
        session.flush()

        UserStripe(user).unlink_from_plan(Plan.paid())

        assert not unsubscribe_successful.called
        assert unsubscribe_not_required.called_once
    def test_delete_customer(self, app):
        """ Delete a Stripe Customer """

        user = StripedUserFactory(tier="paid",
                                  email="*****@*****.**",
                                  stripe__payment_method="pm_card_visa")
        uss = UserStripe(user)
        uss.link_to_plan(Plan.paid())

        customer_id = user.stripe_id

        UserStripe(user).delete_stripe_customer()

        cus = stripe.Customer.retrieve(customer_id)
        assert cus.deleted is True
        assert user.plan == Plan.free()
    def test_user_fails_to_subscribe_decline(
        self,
        subscribed_successfully,
        subscribed_failed,
        subscription_requires_action,
        session,
    ):
        """ User's card was declined when paying """
        # This is the 40000000341 card that will fail when a charge is initiated
        user = StripedUserFactory(
            tier="paid", stripe__payment_method="pm_card_chargeCustomerFail")
        session.add(user)
        session.flush()

        UserStripe(user).link_to_plan(user.plan)

        assert not subscribed_successfully.called
        assert not subscription_requires_action.called
        assert subscribed_failed.called_once
        assert user.plan == Plan.free()
    def test_user_fails_to_subscribe_security(
        self,
        subscribed_failed,
        subscribed_successfully,
        subscription_requires_action,
        session,
    ):
        """ User payment failed becaues of additional security
            measures on their account """
        user = StripedUserFactory(
            tier="paid",
            stripe__payment_method="pm_card_threeDSecure2Required")
        session.add(user)
        session.flush()

        UserStripe(user).link_to_plan(user.plan)

        assert not subscribed_successfully.called
        assert not subscribed_failed.called
        assert subscription_requires_action.called
        assert user.plan == Plan.free()
Пример #11
0
    def update_stripe_customer(self, updated_field) -> bool:
        if self.user.plan == Plan.free():
            # we don't need to do anything
            return True

        uns = UserNotification(self.user)
        subscription = self._retrieve_users_subscriptions(self.user.plan)
        if subscription:
            if updated_field == "stripe_payment_method":
                stripe.Subscription.modify(
                    subscription.id,
                    default_payment_method=self.user.stripe_payment_method,
                )
                return True
            else:
                uns.unsubscribe_required()
                return False
        else:
            raise UserError(
                detail="User #{user_id} has no subscription and is not on free plan"
            )
Пример #12
0
    def test_after_commit_hooks_are_specific_to_a_session(
        self, user_subscribed, session, app
    ):

        # What does this test prove? Well - we start by showing
        # the thing works and by setting up a an "after_commit" hook
        # on the session.  (There SHOULD BE one session per request.)
        # The next request should NOT fire the "after_commit" hook
        # because it has a new session.  IE - we are not leaking
        # Model instances across requests, and not firing subscribe
        # events for instances we didn't change

        free_user = UserFactory(tier="free")

        UserUpdate(
            user=free_user,
            rels={"plan": {"data": {"type": "plan", "id": str(Plan.paid().id)}}},
        ).update()

        session.commit()
        session.expire_all()

        user_subscribed.assert_called_with(free_user.id, Plan.paid().id)
        user_subscribed.reset_mock()

        sess = db.create_scoped_session()

        free_user2 = UserFactory(tier="free", email="*****@*****.**")

        UserUpdate(
            user=free_user2,
            rels={"plan": {"data": {"type": "plan", "id": str(Plan.free().id)}}},
        ).update()

        session.commit()

        user_subscribed.assert_not_called()

        sess.remove()
Пример #13
0
 def unlink_from_plan_via_subscription(self, sub_id):
     # This is a "stripe to database" subscription - so we don't need to
     # fire the callbacks that sync stripe
     stripe.Subscription.delete(sub_id, expand=["plan"])
     self.user.plan = Plan.free()