Example #1
0
 def setUp(self):
     from billy.models.company import CompanyModel
     from billy.models.customer import CustomerModel
     from billy.models.plan import PlanModel
     super(TestSubscriptionModel, self).setUp()
     # build the basic scenario for plan model
     self.company_model = CompanyModel(self.session)
     self.customer_model = CustomerModel(self.session)
     self.plan_model = PlanModel(self.session)
     with db_transaction.manager:
         self.company_guid = self.company_model.create('my_secret_key')
         self.daily_plan_guid = self.plan_model.create(
             company_guid=self.company_guid,
             plan_type=self.plan_model.TYPE_CHARGE,
             amount=10,
             frequency=self.plan_model.FREQ_DAILY,
         )
         self.weekly_plan_guid = self.plan_model.create(
             company_guid=self.company_guid,
             plan_type=self.plan_model.TYPE_CHARGE,
             amount=10,
             frequency=self.plan_model.FREQ_WEEKLY,
         )
         self.monthly_plan_guid = self.plan_model.create(
             company_guid=self.company_guid,
             plan_type=self.plan_model.TYPE_CHARGE,
             amount=10,
             frequency=self.plan_model.FREQ_MONTHLY,
         )
         self.customer_tom_guid = self.customer_model.create(
             company_guid=self.company_guid, )
Example #2
0
 def setUp(self):
     from billy.models.company import CompanyModel
     from billy.models.customer import CustomerModel
     from billy.models.plan import PlanModel
     from billy.models.subscription import SubscriptionModel
     super(TestTransactionModel, self).setUp()
     # build the basic scenario for transaction model
     self.company_model = CompanyModel(self.session)
     self.customer_model = CustomerModel(self.session)
     self.plan_model = PlanModel(self.session)
     self.subscription_model = SubscriptionModel(self.session)
     with db_transaction.manager:
         self.company_guid = self.company_model.create('my_secret_key')
         self.plan_guid = self.plan_model.create(
             company_guid=self.company_guid,
             plan_type=self.plan_model.TYPE_CHARGE,
             amount=10,
             frequency=self.plan_model.FREQ_MONTHLY,
         )
         self.customer_guid = self.customer_model.create(
             company_guid=self.company_guid,
         )
         self.subscription_guid = self.subscription_model.create(
             customer_guid=self.customer_guid,
             plan_guid=self.plan_guid,
             payment_uri='/v1/cards/tester',
         )
Example #3
0
    def test_create_subscription_to_other_company_plan(self):
        from billy.models.company import CompanyModel
        from billy.models.plan import PlanModel

        company_model = CompanyModel(self.testapp.session)
        plan_model = PlanModel(self.testapp.session)
        with db_transaction.manager:
            other_company_guid = company_model.create(
                processor_key='MOCK_PROCESSOR_KEY', )
            other_plan_guid = plan_model.create(
                company_guid=other_company_guid,
                frequency=plan_model.FREQ_WEEKLY,
                plan_type=plan_model.TYPE_CHARGE,
                amount=10,
            )

        self.testapp.post(
            '/v1/subscriptions',
            dict(
                customer_guid=self.customer_guid,
                plan_guid=other_plan_guid,
            ),
            extra_environ=dict(REMOTE_USER=self.api_key),
            status=403,
        )
Example #4
0
 def setUp(self):
     from billy.models.company import CompanyModel
     super(TestCustomerModel, self).setUp()
     # build the basic scenario for plan model
     self.company_model = CompanyModel(self.session)
     with transaction.manager:
         self.company_guid = self.company_model.create('my_secret_key')
Example #5
0
def auth_api_key(request):
    """Authenticate API KEY and return corresponding company

    """
    model = CompanyModel(request.session)
    company = model.get_by_api_key(unicode(request.remote_user))
    if company is None:
        raise HTTPForbidden('Invalid API key {}'.format(request.remote_user))
    return company
Example #6
0
 def setUp(self):
     from billy.models.company import CompanyModel
     super(TestCustomerViews, self).setUp()
     model = CompanyModel(self.testapp.session)
     with db_transaction.manager:
         self.company_guid = model.create(
             processor_key='MOCK_PROCESSOR_KEY')
     company = model.get(self.company_guid)
     self.api_key = str(company.api_key)
Example #7
0
def company_list_post(request):
    """Create a new company

    """
    form = validate_form(CompanyCreateForm, request)
    processor_key = form.data['processor_key']

    model = CompanyModel(request.session)
    # TODO: do validation here
    with db_transaction.manager:
        guid = model.create(processor_key=processor_key)
    company = model.get(guid)
    return company
Example #8
0
def company_get(request):
    """Get and return a company

    """
    api_company = auth_api_key(request)
    model = CompanyModel(request.session)
    guid = request.matchdict['company_guid']
    company = model.get(guid)
    if company is None:
        return HTTPNotFound('No such company {}'.format(guid))
    if guid != api_company.guid:
        return HTTPForbidden(
            'You have no premission to access company {}'.format(guid))
    return company
Example #9
0
 def test_get_customer_of_other_company(self):
     from billy.models.company import CompanyModel
     model = CompanyModel(self.testapp.session)
     with db_transaction.manager:
         other_company_guid = model.create(
             processor_key='MOCK_PROCESSOR_KEY')
     other_company = model.get(other_company_guid)
     other_api_key = str(other_company.api_key)
     res = self.testapp.post(
         '/v1/customers',
         extra_environ=dict(REMOTE_USER=other_api_key),
         status=200,
     )
     guid = res.json['guid']
     res = self.testapp.get(
         '/v1/customers/{}'.format(guid),
         extra_environ=dict(REMOTE_USER=self.api_key),
         status=403,
     )
Example #10
0
    def test_create_subscription_to_other_company_customer(self):
        from billy.models.company import CompanyModel
        from billy.models.customer import CustomerModel

        company_model = CompanyModel(self.testapp.session)
        customer_model = CustomerModel(self.testapp.session)
        with db_transaction.manager:
            other_company_guid = company_model.create(
                processor_key='MOCK_PROCESSOR_KEY', )
            other_customer_guid = customer_model.create(
                company_guid=other_company_guid)

        self.testapp.post(
            '/v1/subscriptions',
            dict(
                customer_guid=other_customer_guid,
                plan_guid=self.plan_guid,
            ),
            extra_environ=dict(REMOTE_USER=self.api_key),
            status=403,
        )
Example #11
0
    def test_cancel_subscription_to_other_company(self):
        from billy.models.subscription import SubscriptionModel
        from billy.models.company import CompanyModel

        subscription_model = SubscriptionModel(self.testapp.session)
        company_model = CompanyModel(self.testapp.session)

        with db_transaction.manager:
            subscription_guid = subscription_model.create(
                customer_guid=self.customer_guid,
                plan_guid=self.plan_guid,
            )
            other_company_guid = company_model.create(
                processor_key='MOCK_PROCESSOR_KEY', )
            other_company = company_model.get(other_company_guid)
            other_api_key = str(other_company.api_key)

        self.testapp.post(
            '/v1/subscriptions/{}/cancel'.format(subscription_guid),
            extra_environ=dict(REMOTE_USER=other_api_key),
            status=403,
        )
Example #12
0
 def setUp(self):
     from billy.models.company import CompanyModel
     from billy.models.customer import CustomerModel
     from billy.models.plan import PlanModel
     self.settings = {'billy.processor_factory': DummyProcessor}
     super(TestSubscriptionViews, self).setUp()
     company_model = CompanyModel(self.testapp.session)
     customer_model = CustomerModel(self.testapp.session)
     plan_model = PlanModel(self.testapp.session)
     with db_transaction.manager:
         self.company_guid = company_model.create(
             processor_key='MOCK_PROCESSOR_KEY', )
         self.customer_guid = customer_model.create(
             company_guid=self.company_guid)
         self.plan_guid = plan_model.create(
             company_guid=self.company_guid,
             frequency=plan_model.FREQ_WEEKLY,
             plan_type=plan_model.TYPE_CHARGE,
             amount=10,
         )
     company = company_model.get(self.company_guid)
     self.api_key = str(company.api_key)
Example #13
0
    def test_get_subscription_of_other_company(self):
        from billy.models.company import CompanyModel
        from billy.models.customer import CustomerModel
        from billy.models.plan import PlanModel

        company_model = CompanyModel(self.testapp.session)
        customer_model = CustomerModel(self.testapp.session)
        plan_model = PlanModel(self.testapp.session)
        with db_transaction.manager:
            other_company_guid = company_model.create(
                processor_key='MOCK_PROCESSOR_KEY', )
            other_customer_guid = customer_model.create(
                company_guid=other_company_guid)
            other_plan_guid = plan_model.create(
                company_guid=other_company_guid,
                frequency=plan_model.FREQ_WEEKLY,
                plan_type=plan_model.TYPE_CHARGE,
                amount=10,
            )
        other_company = company_model.get(other_company_guid)
        other_api_key = str(other_company.api_key)

        res = self.testapp.post(
            '/v1/subscriptions',
            dict(
                customer_guid=other_customer_guid,
                plan_guid=other_plan_guid,
            ),
            extra_environ=dict(REMOTE_USER=other_api_key),
            status=200,
        )
        other_guid = res.json['guid']

        self.testapp.get(
            '/v1/subscriptions/{}'.format(other_guid),
            extra_environ=dict(REMOTE_USER=self.api_key),
            status=403,
        )
Example #14
0
 def test_get_plan_of_other_company(self):
     from billy.models.company import CompanyModel
     model = CompanyModel(self.testapp.session)
     with db_transaction.manager:
         other_company_guid = model.create(
             processor_key='MOCK_PROCESSOR_KEY')
     other_company = model.get(other_company_guid)
     other_api_key = str(other_company.api_key)
     res = self.testapp.post(
         '/v1/plans',
         dict(
             plan_type='charge',
             amount='55.66',
             frequency='weekly',
         ),
         extra_environ=dict(REMOTE_USER=other_api_key),
         status=200,
     )
     guid = res.json['guid']
     res = self.testapp.get(
         '/v1/plans/{}'.format(guid),
         extra_environ=dict(REMOTE_USER=self.api_key),
         status=403,
     )
Example #15
0
 def make_one(self, *args, **kwargs):
     from billy.models.company import CompanyModel
     return CompanyModel(*args, **kwargs)
    def create_company_model(self):
        """Create a company model

        """
        return CompanyModel(self)
Example #17
0
    def test_main_with_crash(self):
        from pyramid.paster import get_appsettings
        from billy.models import setup_database
        from billy.models.company import CompanyModel
        from billy.models.customer import CustomerModel
        from billy.models.plan import PlanModel
        from billy.models.subscription import SubscriptionModel
        from billy.scripts import initializedb
        from billy.scripts import process_transactions

        class MockProcessor(object):
            def __init__(self):
                self.charges = {}
                self.tx_sn = 0
                self.called_times = 0

            def create_customer(self, customer):
                return 'MOCK_PROCESSOR_CUSTOMER_ID'

            def prepare_customer(self, customer, payment_uri=None):
                pass

            def charge(self, transaction):
                self.called_times += 1
                if self.called_times == 2:
                    raise KeyboardInterrupt
                guid = transaction.guid
                if guid in self.charges:
                    return self.charges[guid]
                self.charges[guid] = self.tx_sn
                self.tx_sn += 1

        mock_processor = MockProcessor()

        cfg_path = os.path.join(self.temp_dir, 'config.ini')
        with open(cfg_path, 'wt') as f:
            f.write(
                textwrap.dedent("""\
            [app:main]
            use = egg:billy

            sqlalchemy.url = sqlite:///%(here)s/billy.sqlite
            """))
        initializedb.main([initializedb.__file__, cfg_path])

        settings = get_appsettings(cfg_path)
        settings = setup_database({}, **settings)
        session = settings['session']
        company_model = CompanyModel(session)
        customer_model = CustomerModel(session)
        plan_model = PlanModel(session)
        subscription_model = SubscriptionModel(session)

        with db_transaction.manager:
            company_guid = company_model.create('my_secret_key')
            plan_guid = plan_model.create(
                company_guid=company_guid,
                plan_type=plan_model.TYPE_CHARGE,
                amount=10,
                frequency=plan_model.FREQ_MONTHLY,
            )
            customer_guid = customer_model.create(company_guid=company_guid, )
            subscription_model.create(
                customer_guid=customer_guid,
                plan_guid=plan_guid,
                payment_uri='/v1/cards/tester',
            )
            subscription_model.create(
                customer_guid=customer_guid,
                plan_guid=plan_guid,
                payment_uri='/v1/cards/tester',
            )

        with self.assertRaises(KeyboardInterrupt):
            process_transactions.main(
                [process_transactions.__file__, cfg_path],
                processor=mock_processor)

        process_transactions.main([process_transactions.__file__, cfg_path],
                                  processor=mock_processor)

        # here is the story, we have two subscriptions here
        #
        #   Subscription1
        #   Subscription2
        #
        # And the time is not advanced, so we should only have two transactions
        # to be yielded and processed. However, we assume bad thing happens
        # durring the process. We let the second call to charge of processor
        # raises a KeyboardInterrupt error. So, it would look like this
        #
        #   charge for transaction from Subscription1
        #   charge for transaction from Subscription2 (Crash)
        #
        # Then, we perform the process_transactions again, if it works
        # correctly, the first transaction is already yield and processed.
        #
        #   charge for transaction from Subscription2
        #
        # So, there would only be two charges in processor. This is mainly
        # for making sure we won't duplicate charges/payouts
        self.assertEqual(len(mock_processor.charges), 2)