def update(self, user=None, coupon=None, plan=None):
        """
        Update an existing subscription.

        :param user: User to apply the subscription to
        :type user: User instance
        :param coupon: Coupon code to apply
        :type coupon: str
        :param plan: Plan identifier
        :type plan: str
        :return: bool
        """
        PaymentSubscription.update(user.payment_id, coupon, plan)

        user.previous_plan = user.subscription.plan
        user.subscription.plan = plan
        user.coins = add_subscription_coins(user.coins,
                                            Subscription.get_plan_by_id(
                                                user.previous_plan),
                                            Subscription.get_plan_by_id(plan),
                                            user.cancelled_subscription_on)

        if coupon:
            user.subscription.coupon = coupon
            coupon = Coupon.query.filter(Coupon.code == coupon).first()

            if coupon:
                coupon.redeem()

        db.session.add(user.subscription)
        db.session.commit()

        return True
    def create(self, user=None, name=None, plan=None, coupon=None, token=None):
        """
        Create a recurring subscription.

        :param user: User to apply the subscription to
        :type user: User instance
        :param name: User's billing name
        :type name: str
        :param plan: Plan identifier
        :type plan: str
        :param coupon: Coupon code to apply
        :type coupon: str
        :param token: Token returned by JavaScript
        :type token: str
        :return: bool
        """
        if token is None:
            return False

        if coupon:
            self.coupon = coupon.upper()

        customer = PaymentCustomer.create(token=token,
                                          email=user.email,
                                          plan=plan,
                                          coupon=self.coupon)

        # Update the user account.
        user.payment_id = customer.id
        user.name = name
        user.previous_plan = plan
        user.coins = add_subscription_coins(user.coins,
                                            Subscription.get_plan_by_id(
                                                user.previous_plan),
                                            Subscription.get_plan_by_id(plan),
                                            user.cancelled_subscription_on)
        user.cancelled_subscription_on = None

        # Set the subscription details.
        self.user_id = user.id
        self.plan = plan

        # Redeem the coupon.
        if coupon:
            coupon = Coupon.query.filter(Coupon.code == self.coupon).first()
            coupon.redeem()

        # Create the credit card.
        credit_card = CreditCard(user_id=user.id,
                                 **CreditCard.extract_card_params(customer))

        db.session.add(user)
        db.session.add(credit_card)
        db.session.add(self)

        db.session.commit()

        return True
    def test_no_coin_change_for_subscription_downgrade(self):
        """ Same coins for a subscription downgrade. """
        coins = 100

        current_plan = Subscription.get_plan_by_id('gold')
        new_plan = Subscription.get_plan_by_id('bronze')

        coins = add_subscription_coins(coins, current_plan, new_plan, None)

        assert coins == 100
    def test_add_coins_to_subscription_upgrade(self):
        """ Add coins to a subscription upgrade. """
        coins = 100

        current_plan = Subscription.get_plan_by_id('bronze')
        new_plan = Subscription.get_plan_by_id('gold')

        coins = add_subscription_coins(coins, current_plan, new_plan, None)

        assert coins == 590
    def test_no_coin_change_for_same_subscription(self):
        """ Same coins for the same subscription. """
        coins = 100

        current_plan = Subscription.get_plan_by_id('gold')
        new_plan = Subscription.get_plan_by_id('gold')

        may_29_2015 = datetime.datetime(2015, 5, 29, 0, 0, 0)
        may_29_2015 = pytz.utc.localize(may_29_2015)

        coins = add_subscription_coins(coins, current_plan, new_plan,
                                       may_29_2015)

        assert coins == 100