def test_coupon_redemption_direct_discount(self): # add a sample plan to the plans backend mocurly.backend.plans_backend.add_object( self.base_backed_plan_data['plan_code'], self.base_backed_plan_data) # add a sample coupon to the coupons backend base_coupon_data = { 'coupon_code': 'special', 'name': 'Special $1.00 off', 'discount_type': 'dollars', 'discount_in_cents': 100 } mocurly.backend.coupons_backend.add_object( base_coupon_data['coupon_code'], base_coupon_data) # ... and redeem the coupon base_redemption_data = { 'account_code': self.base_account_data['account_code'], 'currency': 'USD', 'coupon': base_coupon_data['coupon_code'] } mocurly.backend.coupon_redemptions_backend.add_object( base_redemption_data['coupon'] + '__' + self.base_account_data['account_code'], base_redemption_data) # Now add an active subscription and verify the transactions are discounted properly new_subscription = recurly.Subscription(**self.base_subscription_data) new_subscription.save() invoice = new_subscription.invoice() self.assertEqual(invoice.total_in_cents, 900) line_items = invoice.line_items self.assertEqual(len(line_items), 1) line_item = line_items[0] self.assertEqual(line_item.unit_amount_in_cents, 1000) self.assertEqual(line_item.discount_in_cents, 100) self.assertEqual(line_item.total_in_cents, 900)
def test_trial_subscription_creation(self): # add a sample plan to the plans backend self.base_backed_plan_data['trial_interval_length'] = 1 mocurly.backend.plans_backend.add_object( self.base_backed_plan_data['plan_code'], self.base_backed_plan_data) self.assertEqual(len(mocurly.backend.subscriptions_backend.datastore), 0) new_subscription = recurly.Subscription(**self.base_subscription_data) new_subscription.save() self.assertEqual(len(mocurly.backend.subscriptions_backend.datastore), 1) # Make sure a new transaction and invoice was created with it invoice = new_subscription.invoice() self.assertEqual(invoice.line_items[0].start_date.date(), datetime.datetime.utcnow().date()) self.assertEqual(invoice.line_items[0].end_date.date(), (datetime.datetime.utcnow() + relativedelta(months=1)).date()) transactions = invoice.transactions self.assertEqual(len(transactions), 1) self.assertEqual(transactions[0].subscription().uuid, new_subscription.uuid) # Make sure we can reference the subscription from the account account = new_subscription.account() account_subscriptions = account.subscriptions() self.assertEqual(len(account_subscriptions), 1) self.assertEqual(account_subscriptions[0].uuid, new_subscription.uuid) self.assertEqual(account_subscriptions[0].state, 'active')
def test_trial_override_subscription_creation(self): # add a sample plan to the plans backend self.base_backed_plan_data['trial_interval_length'] = 1 mocurly.backend.plans_backend.add_object( self.base_backed_plan_data['plan_code'], self.base_backed_plan_data) self.assertEqual(len(mocurly.backend.subscriptions_backend.datastore), 0) # Make the trial immediately expire self.base_subscription_data[ 'trial_ends_at'] = datetime.datetime.utcnow() new_subscription = recurly.Subscription(**self.base_subscription_data) new_subscription.save() self.assertEqual(len(mocurly.backend.subscriptions_backend.datastore), 1) # Make sure a new transaction and invoice was created with it invoice = new_subscription.invoice() # The invoice should not contain 0 (trial cost) but the actual cost of the subscription since the trial has expired immediately self.assertNotEqual(invoice.total_in_cents, 0) transactions = invoice.transactions self.assertEqual(len(transactions), 1) self.assertEqual(transactions[0].subscription().uuid, new_subscription.uuid) # Make sure we can reference the subscription from the account account = new_subscription.account() account_subscriptions = account.subscriptions() self.assertEqual(len(account_subscriptions), 1) self.assertEqual(account_subscriptions[0].uuid, new_subscription.uuid) self.assertEqual(account_subscriptions[0].state, 'active')
def new_subscription(self): try: subscription = recurly.Subscription() subscription.plan_code = 'pro' subscription.currency = 'USD' account = recurly.Account(account_code=uuid.uuid1()) account.email = '*****@*****.**' account.first_name = 'Michael1' account.last_name = 'McGovern' billing_info = recurly.BillingInfo() billing_info.number = '4111-1111-1111-1111' billing_info.month = 05 billing_info.year = 2019 account.billing_info = billing_info subscription.account = account log.warn("========================test========================") subscription.save() except recurly.NotFoundError: print 'Account not Found.\n' except recurly.errors: for e in errors: print "%s:%s" % (e.field, e.message)
def new_subscription(): # We'll wrap this in a try to catch any API # errors that may occur try: # Create the scubscription using minimal # information: plan_code, account_code, currency and # the token we generated on the frontend subscription = recurly.Subscription( plan_code='basic', currency='USD', account=recurly.Account( account_code=uuid.uuid1(), billing_info=recurly.BillingInfo( token_id=request.form['recurly-token']))) # The subscription has been created and we can redirect # to a confirmation page subscription.save() return redirect('SUCCESS_URL') except recurly.ValidationError, errors: # Here we may wish to log the API error and send the # customer to an appropriate URL, perhaps including # and error message. See the `error_redirect` and # `compose_errors` functions below. error_redirect(compose_errors(errors))
def new_subscription(): # If user is not logged in, have them login or register if not current_user.is_authenticated: flash('Please login or register to create an account first!', 'danger') return redirect(url_for('users.login')) # We'll wrap this in a try to catch any API # errors that may occur try: # Get the user_account user_account_code = fa.create_account_code(current_user.id) user_account = recurly.Account.get(user_account_code) billing_info = recurly.BillingInfo( token_id=request.form['recurly-token']) user_account.billing_info = billing_info # Create the scubscription using minimal # information: plan_code, account_code, currency and # the token we generated on the frontend subscription = recurly.Subscription(currency='USD', account=user_account, plan_code='testplancode') except: flash(('Sorry, our servers experienced an issue creating your' 'subscription. Please try again later!'), 'danger') # The subscription has been created and we can redirect to a confirmation page subscription.save() flash('You have been successfully subscribed to the Basic Plan!', 'success') return redirect(url_for('main.home'))
def new_recurly_account(): # If user is not logged in, have them login or register if not current_user.is_authenticated: flash('Please login or register to create an account first!', 'danger') return redirect(url_for('users.login')) # Create user's account_code from hidden hash library user_account_code = fa.create_account_code(current_user.id) try: # Create user account new_account = recurly.Account( account_code=user_account_code, billing_info=recurly.BillingInfo( token_id=request.form['recurly-token'])) # Create subscription subscription = recurly.Subscription() subscription.plan_code = request.form['plan'] subscription.currency = 'USD' subscription.account = new_account subscription.save() flash('Account subscribed successfully!', 'success') return redirect(url_for('users.account')) except recurly.ValidationError: flash('ValidationError! Please try again shortly.', 'danger') return redirect(url_for('users.account'))
def create_remote_subsciption(subscription_params, account_params, billing_info_params=None): assert "account" not in subscription_params, subscription_params recurly_account = _construct_recurly_account_resource( account_params, billing_info_params=billing_info_params) subscription_params = copy.deepcopy( subscription_params) # do not touch input object subscription_params["account"] = recurly_account recurly_subscription = recurly.Subscription(**subscription_params) return recurly_subscription
def new_subscription(): # We'll wrap this in a try to catch any API # errors that may occur try: recurly_token_id = request.form['recurly-token'] if 'recurly-account-code' in request.form: recurly_account_code = request.form['recurly-account-code'] else: recurly_account_code = uuid.uuid1() # Build our billing info object billing_info = recurly.BillingInfo(token_id=recurly_token_id) # Optionally add a 3D Secure token if one is present. You only need to do this # if you are integrating with Recurly's 3D Secure support if 'three-d-secure-token' in request.form: billing_info.three_d_secure_action_result_token_id = request.form[ 'three-d-secure-token'] # Create the scubscription using minimal # information: plan_code, account_code, currency and # the token we generated on the frontend subscription = recurly.Subscription( plan_code='basic', currency='USD', account=recurly.Account(account_code=recurly_account_code, billing_info=billing_info)) # The subscription has been created and we can redirect # to a confirmation page subscription.save() return redirect(SUCCESS_URL) except recurly.ValidationError as error: # Here we handle a 3D Secure required error by redirecting to an authentication page if error.transaction_error_code == 'three_d_secure_action_required': action_token_id = error.transaction_error.three_d_secure_action_token_id return redirect("/3d-secure/authenticate.html#token_id=" + recurly_token_id + "&action_token_id=" + action_token_id + "&account_code=" + str(recurly_account_code)) # Here we may wish to log the API error and send the # customer to an appropriate URL, perhaps including # and error message. See the `error_redirect` and # `compose_errors` functions below. error_redirect(compose_errors(error))
def test_subscription_termination_full_refund(self): # add a sample plan to the plans backend mocurly.backend.plans_backend.add_object( self.base_backed_plan_data['plan_code'], self.base_backed_plan_data) # add an active subscription new_subscription = recurly.Subscription(**self.base_subscription_data) new_subscription.save() self.assertEqual(new_subscription.state, 'active') # Now terminate it with a full refund new_subscription.terminate(refund='full') self.assertEqual(new_subscription.state, 'expired') invoice = new_subscription.invoice() transactions = invoice.transactions self.assertEqual(len(transactions), 1) self.assertEqual(transactions[0].status, 'void')
def test_subscription_cancel_reactivate(self): # add a sample plan to the plans backend mocurly.backend.plans_backend.add_object( self.base_backed_plan_data['plan_code'], self.base_backed_plan_data) # add an active subscription new_subscription = recurly.Subscription(**self.base_subscription_data) new_subscription.save() self.assertEqual(new_subscription.state, 'active') # trying to reactivate an active subscription should fail with self.assertRaises(BadRequestError): new_subscription.reactivate() # now cancel it and verify it was canceled new_subscription.cancel() self.assertEqual(new_subscription.state, 'canceled') # now reactivate it and verify it was reactivated new_subscription.reactivate() self.assertEqual(new_subscription.state, 'active') self.assertEqual(new_subscription.canceled_at, None) self.assertEqual(new_subscription.expires_at, None)
def test_subscriptions_with_addons(self): # add a sample plan to the plans backend mocurly.backend.plans_backend.add_object( self.base_backed_plan_data['plan_code'], self.base_backed_plan_data) # add some add ons to the backend for add_on in self.base_add_on_backed_data: uuid = mocurly.endpoints.PlansEndpoint().generate_plan_add_on_uuid( self.base_backed_plan_data['plan_code'], add_on['add_on_code']) mocurly.backend.plan_add_ons_backend.add_object(uuid, add_on) self.assertEqual(len(mocurly.backend.subscriptions_backend.datastore), 0) self.base_subscription_data['subscription_add_ons'] = [ recurly.SubscriptionAddOn(add_on_code=addon['add_on_code'], quantity=1) for addon in self.base_add_on_data ] new_subscription = recurly.Subscription(**self.base_subscription_data) new_subscription.save() self.assertEqual(len(mocurly.backend.subscriptions_backend.datastore), 1)
def test_subscription_termination_partial_refund(self): # add a sample plan to the plans backend mocurly.backend.plans_backend.add_object( self.base_backed_plan_data['plan_code'], self.base_backed_plan_data) # add an active subscription new_subscription = recurly.Subscription(**self.base_subscription_data) new_subscription.save() self.assertEqual(new_subscription.state, 'active') # modify start time so a partial refund will refund half the cost start = new_subscription.current_period_started_at end = new_subscription.current_period_ends_at new_start = start - (end - start) mocurly.backend.subscriptions_backend.update_object( new_subscription.uuid, {'current_period_started_at': new_start.isoformat()}) # get the original transaction and invoice objects for use later self.assertEqual(len(mocurly.backend.transactions_backend.datastore), 1) self.assertEqual(len(mocurly.backend.invoices_backend.datastore), 1) transaction_keys = iterkeys( mocurly.backend.transactions_backend.datastore) invoice_keys = iterkeys(mocurly.backend.invoices_backend.datastore) original_transaction_id = next(transaction_keys) original_invoice_id = next(invoice_keys) # Now terminate it with a partial refund new_subscription.terminate(refund='partial') self.assertEqual(new_subscription.state, 'expired') self.assertEqual(len(mocurly.backend.transactions_backend.datastore), 2) self.assertEqual(len(mocurly.backend.invoices_backend.datastore), 2) for invoice_id, invoice in mocurly.backend.invoices_backend.datastore.items( ): if invoice_id == original_invoice_id: original_invoice = invoice else: refund_invoice = invoice # The following two lines reference the objects to make sure they exist original_invoice refund_invoice original_transaction_ids = original_invoice['transactions'] self.assertEqual(len(original_transaction_ids), 1) self.assertEqual(original_transaction_ids[0], original_transaction_id) original_transaction = mocurly.backend.transactions_backend.get_object( original_transaction_id) self.assertEqual(original_transaction['status'], 'success') # not voided refund_transaction_ids = refund_invoice['transactions'] self.assertEqual(len(refund_transaction_ids), 1) self.assertNotEqual(refund_transaction_ids[0], original_transaction_id) refund_transaction = mocurly.backend.transactions_backend.get_object( refund_transaction_ids[0]) self.assertEqual(refund_transaction['status'], 'success') self.assertEqual(refund_transaction['action'], 'refund') # 29 / 60, because today doesn't count self.assertEqual( refund_transaction['amount_in_cents'], -int(original_transaction['amount_in_cents'] * (29.0 / 60)))
def create(cls, plan, account, subscription_add_ons=None, coupon_code=None, unit_amount=None, currency='USD', quantity=1, trial_ends_at=None, starts_at=None, total_billing_cycles=None, first_renewal_date=None): recurly_account = account.recurly_account recurly_subscription = recurly.Subscription(plan_code=plan.plan_code, account=recurly_account, currency=currency) if coupon_code is not None: recurly_subscription.coupon_code = coupon_code if unit_amount is None: unit_amount = plan.unit_amount # use plan's unit amount as default if none is provided. recurly_subscription.unit_amount_in_cents = int(plan.unit_amount * 100) else: recurly_subscription.unit_amount_in_cents = int(unit_amount * 100) if quantity is not None: recurly_subscription.quantity = quantity if trial_ends_at is not None: recurly_subscription.trial_ends_at = trial_ends_at if starts_at is not None: recurly_subscription.starts_at = starts_at if total_billing_cycles is not None: recurly_subscription.total_billing_cycles = total_billing_cycles if first_renewal_date is not None: recurly_subscription.first_renewal_date = first_renewal_date if subscription_add_ons is not None: #TODO Add-ons pass recurly_subscription.save() return cls._create_local( account=account, plan=plan, uuid=recurly_subscription.uuid, state=recurly_subscription.state, unit_amount=unit_amount, currency=currency, quantity=quantity, activated_at=recurly_subscription.activated_at, canceled_at=recurly_subscription.canceled_at, expires_at=recurly_subscription.expires_at, current_period_started_at=recurly_subscription. current_period_started_at, current_period_ends_at=recurly_subscription.current_period_ends_at, trial_started_at=recurly_subscription.trial_started_at, trial_ends_at=recurly_subscription.trial_ends_at)