def test_monthly_schedule_with_end_of_month(self): with freeze_time('2013-08-31'): now = utc_now() self.assert_schedule(started_at=now, frequency=self.plan_model.frequencies.MONTHLY, interval=1, length=7, expected=[ utc_datetime(2013, 8, 31), utc_datetime(2013, 9, 30), utc_datetime(2013, 10, 31), utc_datetime(2013, 11, 30), utc_datetime(2013, 12, 31), utc_datetime(2014, 1, 31), utc_datetime(2014, 2, 28), ]) with freeze_time('2013-11-30'): now = utc_now() self.assert_schedule(started_at=now, frequency=self.plan_model.frequencies.MONTHLY, interval=1, length=6, expected=[ utc_datetime(2013, 11, 30), utc_datetime(2013, 12, 30), utc_datetime(2014, 1, 30), utc_datetime(2014, 2, 28), utc_datetime(2014, 3, 30), utc_datetime(2014, 4, 30), ])
def test_monthly_schedule_with_end_of_month(self): with freeze_time('2013-08-31'): now = utc_now() self.assert_schedule( started_at=now, frequency=self.plan_model.frequencies.MONTHLY, interval=1, length=7, expected=[ utc_datetime(2013, 8, 31), utc_datetime(2013, 9, 30), utc_datetime(2013, 10, 31), utc_datetime(2013, 11, 30), utc_datetime(2013, 12, 31), utc_datetime(2014, 1, 31), utc_datetime(2014, 2, 28), ] ) with freeze_time('2013-11-30'): now = utc_now() self.assert_schedule( started_at=now, frequency=self.plan_model.frequencies.MONTHLY, interval=1, length=6, expected=[ utc_datetime(2013, 11, 30), utc_datetime(2013, 12, 30), utc_datetime(2014, 1, 30), utc_datetime(2014, 2, 28), utc_datetime(2014, 3, 30), utc_datetime(2014, 4, 30), ] )
def test_invalid_interval(self): with self.assertRaises(ValueError): next_transaction_datetime( started_at=utc_now(), frequency=self.plan_model.frequencies.DAILY, period=0, interval=0, ) with self.assertRaises(ValueError): next_transaction_datetime( started_at=utc_now(), frequency=self.plan_model.frequencies.DAILY, period=0, interval=-1, )
def test_invalid_interval(self): with self.assertRaises(ValueError): next_transaction_datetime( started_at=utc_now(), frequency=self.plan_model.frequencies.DAILY, period=0, interval=0, ) with self.assertRaises(ValueError): next_transaction_datetime( started_at=utc_now(), frequency=self.plan_model.frequencies.DAILY, period=0, interval=-1, )
def test_create_customer( self, create_customer_method, validate_customer_method, configure_api_key_method, ): now = utc_now() now_iso = now.isoformat() validate_customer_method.return_value = True res = self.testapp.post( '/v1/customers', dict(processor_uri='MOCK_CUSTOMER_URI'), extra_environ=dict(REMOTE_USER=self.api_key), status=200, ) self.failUnless('guid' in res.json) self.assertEqual(res.json['created_at'], now_iso) self.assertEqual(res.json['updated_at'], now_iso) self.assertEqual(res.json['processor_uri'], 'MOCK_CUSTOMER_URI') self.assertEqual(res.json['company_guid'], self.company.guid) self.assertEqual(res.json['deleted'], False) self.assertFalse(create_customer_method.called) validate_customer_method.assert_called_once_with('MOCK_CUSTOMER_URI') configure_api_key_method.assert_called_once_with('MOCK_PROCESSOR_KEY')
def test_callback_only_latest_event_affects_status(self): time1 = utc_now() time2 = time1 + datetime.timedelta(seconds=10) time3 = time1 + datetime.timedelta(seconds=20) ts = self.transaction_model.statuses vs = self.invoice_model.statuses def assert_status( ev_id, status, time, expected_iv_status, expected_tx_status ): self._do_callback(ev_id, status, time) self.assertEqual(self.transaction.status, expected_tx_status) self.assertEqual(self.invoice.status, expected_iv_status) assert_status('EV_ID_1', 'pending', time1, vs.PROCESSING, ts.PENDING) assert_status('EV_ID_3', 'failed', time3, vs.FAILED, ts.FAILED) # this is the point, EV_ID_2 arrived later than EV_ID_3, but its # occurred_at time is earlier than EV_ID3, so it should never affect # the status of transaction and invoice assert_status('EV_ID_2', 'succeeded', time2, vs.FAILED, ts.FAILED) # ensure events are generated correctly and in right order for event, (expected_ev_id, expected_status, expected_time) in zip( self.transaction.events, [ ('EV_ID_3', ts.FAILED, time3), ('EV_ID_2', ts.SUCCEEDED, time2), ('EV_ID_1', ts.PENDING, time1), ] ): self.assertEqual(event.processor_id, expected_ev_id) self.assertEqual(event.status, expected_status) self.assertEqual(event.occurred_at, expected_time)
def test_create_invoice(self): amount = 5566 title = 'foobar invoice' external_id = 'external ID' appears_on_statement_as = 'hello baby' now = utc_now() now_iso = now.isoformat() res = self.testapp.post( '/v1/invoices', dict( customer_guid=self.customer.guid, amount=amount, title=title, external_id=external_id, appears_on_statement_as=appears_on_statement_as, ), extra_environ=dict(REMOTE_USER=self.api_key), status=200, ) self.failUnless('guid' in res.json) self.assertEqual(res.json['created_at'], now_iso) self.assertEqual(res.json['updated_at'], now_iso) self.assertEqual(res.json['amount'], amount) self.assertEqual(res.json['title'], title) self.assertEqual(res.json['external_id'], external_id) self.assertEqual(res.json['appears_on_statement_as'], appears_on_statement_as) self.assertEqual(res.json['customer_guid'], self.customer.guid) self.assertEqual(res.json['funding_instrument_uri'], None) invoice = self.invoice_model.get(res.json['guid']) self.assertEqual(len(invoice.transactions), 0)
def test_callback_only_latest_event_affects_status(self): time1 = utc_now() time2 = time1 + datetime.timedelta(seconds=10) time3 = time1 + datetime.timedelta(seconds=20) ts = self.transaction_model.statuses vs = self.invoice_model.statuses def assert_status(ev_id, status, time, expected_iv_status, expected_tx_status): self._do_callback(ev_id, status, time) self.assertEqual(self.transaction.status, expected_tx_status) self.assertEqual(self.invoice.status, expected_iv_status) assert_status('EV_ID_1', 'pending', time1, vs.PROCESSING, ts.PENDING) assert_status('EV_ID_3', 'failed', time3, vs.FAILED, ts.FAILED) # this is the point, EV_ID_2 arrived later than EV_ID_3, but its # occurred_at time is earlier than EV_ID3, so it should never affect # the status of transaction and invoice assert_status('EV_ID_2', 'succeeded', time2, vs.FAILED, ts.FAILED) # ensure events are generated correctly and in right order for event, (expected_ev_id, expected_status, expected_time) in zip(self.transaction.events, [ ('EV_ID_3', ts.FAILED, time3), ('EV_ID_2', ts.SUCCEEDED, time2), ('EV_ID_1', ts.PENDING, time1), ]): self.assertEqual(event.processor_id, expected_ev_id) self.assertEqual(event.status, expected_status) self.assertEqual(event.occurred_at, expected_time)
def make_event( self, event_id='EV_MOCK_EVENT_ID', transaction_guid=None, occurred_at=None, status='succeeded', ): """Make a mock Balanced.Event instance and return """ if transaction_guid is None: transaction_guid = self.transaction.guid if occurred_at is None: occurred_at = utc_now() event = mock.Mock( id=event_id, occurred_at=occurred_at, entity=dict( entity_type=[dict( meta={'billy.transaction_guid': transaction_guid}, status=status, )], links=[], ) ) return event
def test_create_customer( self, create_customer_method, validate_customer_method, configure_api_key_method, ): now = utc_now() now_iso = now.isoformat() validate_customer_method.return_value = True res = self.testapp.post( '/v1/customers', dict(processor_uri='MOCK_CUSTOMER_URI'), extra_environ=dict(REMOTE_USER=self.api_key), status=200, ) self.failUnless('guid' in res.json) self.assertEqual(res.json['created_at'], now_iso) self.assertEqual(res.json['updated_at'], now_iso) self.assertEqual(res.json['processor_uri'], 'MOCK_CUSTOMER_URI') self.assertEqual(res.json['company_guid'], self.company.guid) self.assertEqual(res.json['deleted'], False) self.assertFalse(create_customer_method.called) validate_customer_method.assert_called_once_with('MOCK_CUSTOMER_URI') configure_api_key_method.assert_called_once_with('MOCK_PROCESSOR_KEY')
def test_create_plan(self): plan_type = 'debit' amount = 5566 frequency = 'weekly' interval = 123 now = utc_now() now_iso = now.isoformat() res = self.testapp.post( '/v1/plans', dict( plan_type=plan_type, amount=amount, frequency=frequency, interval=interval, ), extra_environ=dict(REMOTE_USER=self.api_key), status=200, ) self.failUnless('guid' in res.json) self.assertEqual(res.json['created_at'], now_iso) self.assertEqual(res.json['updated_at'], now_iso) self.assertEqual(res.json['plan_type'], plan_type) self.assertEqual(res.json['amount'], amount) self.assertEqual(res.json['frequency'], frequency) self.assertEqual(res.json['interval'], interval) self.assertEqual(res.json['company_guid'], self.company.guid) self.assertEqual(res.json['deleted'], False)
def test_create_subscription_with_started_at(self): amount = 5566 now = utc_now() now_iso = now.isoformat() # next week next_invoice_at = utc_datetime(2013, 8, 17) next_iso = next_invoice_at.isoformat() res = self.testapp.post( '/v1/subscriptions', dict( customer_guid=self.customer.guid, plan_guid=self.plan.guid, amount=amount, started_at='2013-08-17T00:00:00Z', ), extra_environ=dict(REMOTE_USER=self.api_key), status=200, ) self.failUnless('guid' in res.json) self.assertEqual(res.json['created_at'], now_iso) self.assertEqual(res.json['updated_at'], now_iso) self.assertEqual(res.json['next_invoice_at'], next_iso) self.assertEqual(res.json['invoice_count'], 0) self.assertEqual(res.json['amount'], amount) self.assertEqual(res.json['customer_guid'], self.customer.guid) self.assertEqual(res.json['plan_guid'], self.plan.guid)
def test_create_invoice(self): amount = 5566 title = 'foobar invoice' external_id = 'external ID' appears_on_statement_as = 'hello baby' now = utc_now() now_iso = now.isoformat() res = self.testapp.post( '/v1/invoices', dict( customer_guid=self.customer.guid, amount=amount, title=title, external_id=external_id, appears_on_statement_as=appears_on_statement_as, ), extra_environ=dict(REMOTE_USER=self.api_key), status=200, ) self.failUnless('guid' in res.json) self.assertEqual(res.json['created_at'], now_iso) self.assertEqual(res.json['updated_at'], now_iso) self.assertEqual(res.json['amount'], amount) self.assertEqual(res.json['title'], title) self.assertEqual(res.json['external_id'], external_id) self.assertEqual(res.json['appears_on_statement_as'], appears_on_statement_as) self.assertEqual(res.json['customer_guid'], self.customer.guid) self.assertEqual(res.json['funding_instrument_uri'], None) invoice = self.invoice_model.get(res.json['guid']) self.assertEqual(len(invoice.transactions), 0)
def make_event( self, event_id='EV_MOCK_EVENT_ID', transaction_guid=None, occurred_at=None, status='succeeded', ): """Make a mock Balanced.Event instance and return """ if transaction_guid is None: transaction_guid = self.transaction.guid if occurred_at is None: occurred_at = utc_now() event = mock.Mock( id=event_id, occurred_at=occurred_at, entity=dict( entity_type=[ dict( meta={'billy.transaction_guid': transaction_guid}, status=status, ) ], links=[], )) return event
def test_create_subscription_with_started_at(self): amount = 5566 now = utc_now() now_iso = now.isoformat() # next week next_invoice_at = utc_datetime(2013, 8, 17) next_iso = next_invoice_at.isoformat() res = self.testapp.post( '/v1/subscriptions', dict( customer_guid=self.customer.guid, plan_guid=self.plan.guid, amount=amount, started_at='2013-08-17T00:00:00Z', ), extra_environ=dict(REMOTE_USER=self.api_key), status=200, ) self.failUnless('guid' in res.json) self.assertEqual(res.json['created_at'], now_iso) self.assertEqual(res.json['updated_at'], now_iso) self.assertEqual(res.json['next_invoice_at'], next_iso) self.assertEqual(res.json['invoice_count'], 0) self.assertEqual(res.json['amount'], amount) self.assertEqual(res.json['customer_guid'], self.customer.guid) self.assertEqual(res.json['plan_guid'], self.plan.guid)
def assert_next_day(now_dt, expected): with freeze_time(now_dt): now = utc_now() next_dt = next_transaction_datetime( started_at=now, frequency=self.plan_model.frequencies.DAILY, period=1, ) self.assertEqual(next_dt, expected)
def assert_next_day(now_dt, expected): with freeze_time(now_dt): now = utc_now() next_dt = next_transaction_datetime( started_at=now, frequency=self.plan_model.frequencies.DAILY, period=1, ) self.assertEqual(next_dt, expected)
def test_yearly_schedule_with_interval(self): with freeze_time('2013-08-18'): now = utc_now() self.assert_schedule(started_at=now, frequency=self.plan_model.frequencies.YEARLY, interval=2, length=3, expected=[ utc_datetime(2013, 8, 18), utc_datetime(2015, 8, 18), utc_datetime(2017, 8, 18), ])
def test_yearly_schedule_with_interval(self): with freeze_time('2013-08-18'): now = utc_now() self.assert_schedule( started_at=now, frequency=self.plan_model.frequencies.YEARLY, interval=2, length=3, expected=[ utc_datetime(2013, 8, 18), utc_datetime(2015, 8, 18), utc_datetime(2017, 8, 18), ])
def test_monthly_schedule_with_interval(self): with freeze_time('2013-08-18'): now = utc_now() self.assert_schedule(started_at=now, frequency=self.plan_model.frequencies.MONTHLY, interval=6, length=4, expected=[ utc_datetime(2013, 8, 18), utc_datetime(2014, 2, 18), utc_datetime(2014, 8, 18), utc_datetime(2015, 2, 18), ])
def test_daily_schedule_with_interval(self): with freeze_time('2013-07-28'): now = utc_now() self.assert_schedule(started_at=now, frequency=self.plan_model.frequencies.DAILY, interval=3, length=4, expected=[ utc_datetime(2013, 7, 28), utc_datetime(2013, 7, 31), utc_datetime(2013, 8, 3), utc_datetime(2013, 8, 6), ])
def test_weekly_schedule(self): with freeze_time('2013-08-18'): now = utc_now() self.assert_schedule(started_at=now, frequency=self.plan_model.frequencies.WEEKLY, interval=1, length=5, expected=[ utc_datetime(2013, 8, 18), utc_datetime(2013, 8, 25), utc_datetime(2013, 9, 1), utc_datetime(2013, 9, 8), utc_datetime(2013, 9, 15), ])
def test_yearly_schedule_with_leap_year(self): with freeze_time('2012-02-29'): now = utc_now() self.assert_schedule(started_at=now, frequency=self.plan_model.frequencies.YEARLY, interval=1, length=5, expected=[ utc_datetime(2012, 2, 29), utc_datetime(2013, 2, 28), utc_datetime(2014, 2, 28), utc_datetime(2015, 2, 28), utc_datetime(2016, 2, 29), ])
def test_monthly_schedule_with_interval(self): with freeze_time('2013-08-18'): now = utc_now() self.assert_schedule( started_at=now, frequency=self.plan_model.frequencies.MONTHLY, interval=6, length=4, expected=[ utc_datetime(2013, 8, 18), utc_datetime(2014, 2, 18), utc_datetime(2014, 8, 18), utc_datetime(2015, 2, 18), ] )
def test_daily_schedule_with_interval(self): with freeze_time('2013-07-28'): now = utc_now() self.assert_schedule( started_at=now, frequency=self.plan_model.frequencies.DAILY, interval=3, length=4, expected=[ utc_datetime(2013, 7, 28), utc_datetime(2013, 7, 31), utc_datetime(2013, 8, 3), utc_datetime(2013, 8, 6), ] )
def test_yearly_schedule_with_leap_year(self): with freeze_time('2012-02-29'): now = utc_now() self.assert_schedule( started_at=now, frequency=self.plan_model.frequencies.YEARLY, interval=1, length=5, expected=[ utc_datetime(2012, 2, 29), utc_datetime(2013, 2, 28), utc_datetime(2014, 2, 28), utc_datetime(2015, 2, 28), utc_datetime(2016, 2, 29), ] )
def test_weekly_schedule(self): with freeze_time('2013-08-18'): now = utc_now() self.assert_schedule( started_at=now, frequency=self.plan_model.frequencies.WEEKLY, interval=1, length=5, expected=[ utc_datetime(2013, 8, 18), utc_datetime(2013, 8, 25), utc_datetime(2013, 9, 1), utc_datetime(2013, 9, 8), utc_datetime(2013, 9, 15), ] )
def test_create_invoice_with_funding_instrument_uri(self, debit_method): amount = 5566 funding_instrument_uri = 'MOCK_CARD_URI' now = utc_now() now_iso = now.isoformat() adjustments = [ dict(amount=-100, reason='A Lannister always pays his debts!'), ] adjustment_params = self._encode_adjustment_params(adjustments) debit_method.return_value = dict( processor_uri='MOCK_DEBIT_URI', status=self.transaction_model.statuses.SUCCEEDED, ) res = self.testapp.post( '/v1/invoices', dict( customer_guid=self.customer.guid, amount=amount, funding_instrument_uri=funding_instrument_uri, **adjustment_params ), extra_environ=dict(REMOTE_USER=self.api_key), status=200, ) self.failUnless('guid' in res.json) self.assertEqual(res.json['created_at'], now_iso) self.assertEqual(res.json['updated_at'], now_iso) self.assertEqual(res.json['amount'], amount) self.assertEqual(res.json['effective_amount'], amount - 100) self.assertEqual(res.json['title'], None) self.assertEqual(res.json['customer_guid'], self.customer.guid) self.assertEqual(res.json['funding_instrument_uri'], funding_instrument_uri) invoice = self.invoice_model.get(res.json['guid']) self.assertEqual(len(invoice.transactions), 1) transaction = invoice.transactions[0] self.assertEqual(transaction.amount, invoice.effective_amount) self.assertEqual(transaction.processor_uri, 'MOCK_DEBIT_URI') self.assertEqual(transaction.submit_status, self.transaction_model.submit_statuses.DONE) self.assertEqual(transaction.status, self.transaction_model.statuses.SUCCEEDED) debit_method.assert_called_once_with(transaction)
def test_cancel_subscription(self): with db_transaction.manager: subscription = self.subscription_model.create( customer=self.customer, plan=self.plan, ) with freeze_time('2013-08-16 07:00:00'): canceled_at = utc_now() res = self.testapp.post( '/v1/subscriptions/{}/cancel'.format(subscription.guid), extra_environ=dict(REMOTE_USER=self.api_key), status=200, ) subscription = res.json self.assertEqual(subscription['canceled'], True) self.assertEqual(subscription['canceled_at'], canceled_at.isoformat())
def test_cancel_subscription(self): with db_transaction.manager: subscription = self.subscription_model.create( customer=self.customer, plan=self.plan, ) with freeze_time('2013-08-16 07:00:00'): canceled_at = utc_now() res = self.testapp.post( '/v1/subscriptions/{}/cancel'.format(subscription.guid), extra_environ=dict(REMOTE_USER=self.api_key), status=200, ) subscription = res.json self.assertEqual(subscription['canceled'], True) self.assertEqual(subscription['canceled_at'], canceled_at.isoformat())
def test_create_invoice_with_funding_instrument_uri(self, debit_method): amount = 5566 funding_instrument_uri = 'MOCK_CARD_URI' now = utc_now() now_iso = now.isoformat() adjustments = [ dict(amount=-100, reason='A Lannister always pays his debts!'), ] adjustment_params = self._encode_adjustment_params(adjustments) debit_method.return_value = dict( processor_uri='MOCK_DEBIT_URI', status=self.transaction_model.statuses.SUCCEEDED, ) res = self.testapp.post( '/v1/invoices', dict(customer_guid=self.customer.guid, amount=amount, funding_instrument_uri=funding_instrument_uri, **adjustment_params), extra_environ=dict(REMOTE_USER=self.api_key), status=200, ) self.failUnless('guid' in res.json) self.assertEqual(res.json['created_at'], now_iso) self.assertEqual(res.json['updated_at'], now_iso) self.assertEqual(res.json['amount'], amount) self.assertEqual(res.json['effective_amount'], amount - 100) self.assertEqual(res.json['title'], None) self.assertEqual(res.json['customer_guid'], self.customer.guid) self.assertEqual(res.json['funding_instrument_uri'], funding_instrument_uri) invoice = self.invoice_model.get(res.json['guid']) self.assertEqual(len(invoice.transactions), 1) transaction = invoice.transactions[0] self.assertEqual(transaction.amount, invoice.effective_amount) self.assertEqual(transaction.processor_uri, 'MOCK_DEBIT_URI') self.assertEqual(transaction.submit_status, self.transaction_model.submit_statuses.DONE) self.assertEqual(transaction.status, self.transaction_model.statuses.SUCCEEDED) debit_method.assert_called_once_with(transaction)
def test_create_company(self, register_callback_method): processor_key = 'MOCK_PROCESSOR_KEY' now = utc_now() now_iso = now.isoformat() res = self.testapp.post('/v1/companies', dict(processor_key=processor_key), status=200) self.failUnless('processor_key' not in res.json) self.failUnless('guid' in res.json) self.failUnless('api_key' in res.json) self.assertEqual(res.json['created_at'], now_iso) self.assertEqual(res.json['updated_at'], now_iso) company = self.company_model.get(res.json['guid']) expected_url = 'http://localhost/v1/companies/{}/callbacks/{}/'.format( company.guid, company.callback_key, ) register_callback_method.assert_called_once_with(company, expected_url)
def test_create_company(self, register_callback_method): processor_key = 'MOCK_PROCESSOR_KEY' now = utc_now() now_iso = now.isoformat() res = self.testapp.post( '/v1/companies', dict(processor_key=processor_key), status=200 ) self.failUnless('processor_key' not in res.json) self.failUnless('guid' in res.json) self.failUnless('api_key' in res.json) self.assertEqual(res.json['created_at'], now_iso) self.assertEqual(res.json['updated_at'], now_iso) company = self.company_model.get(res.json['guid']) expected_url = 'http://localhost/v1/companies/{}/callbacks/{}/'.format( company.guid, company.callback_key, ) register_callback_method.assert_called_once_with(company, expected_url)
def test_subscription(self): subscription = self.subscription json_data = subscription_adapter(subscription, self.dummy_request) expected = dict( guid=subscription.guid, amount=None, effective_amount=subscription.plan.amount, funding_instrument_uri=subscription.funding_instrument_uri, appears_on_statement_as=subscription.appears_on_statement_as, invoice_count=subscription.invoice_count, canceled=subscription.canceled, next_invoice_at=subscription.next_invoice_at.isoformat(), created_at=subscription.created_at.isoformat(), updated_at=subscription.updated_at.isoformat(), started_at=subscription.started_at.isoformat(), canceled_at=None, customer_guid=subscription.customer_guid, plan_guid=subscription.plan_guid, ) self.assertEqual(json_data, expected) def assert_amount(amount, expected_amount, expected_effective_amount): subscription.amount = amount json_data = subscription_adapter(subscription, self.dummy_request) self.assertEqual(json_data['amount'], expected_amount) self.assertEqual(json_data['effective_amount'], expected_effective_amount) assert_amount(None, None, subscription.plan.amount) assert_amount(1234, 1234, 1234) def assert_canceled_at(canceled_at, expected_canceled_at): subscription.canceled_at = canceled_at json_data = subscription_adapter(subscription, self.dummy_request) self.assertEqual(json_data['canceled_at'], expected_canceled_at) now = utc_now() assert_canceled_at(None, None) assert_canceled_at(now, now.isoformat())
def test_subscription(self): subscription = self.subscription json_data = subscription_adapter(subscription, self.dummy_request) expected = dict( guid=subscription.guid, amount=None, effective_amount=subscription.plan.amount, funding_instrument_uri=subscription.funding_instrument_uri, appears_on_statement_as=subscription.appears_on_statement_as, invoice_count=subscription.invoice_count, canceled=subscription.canceled, next_invoice_at=subscription.next_invoice_at.isoformat(), created_at=subscription.created_at.isoformat(), updated_at=subscription.updated_at.isoformat(), started_at=subscription.started_at.isoformat(), canceled_at=None, customer_guid=subscription.customer_guid, plan_guid=subscription.plan_guid, ) self.assertEqual(json_data, expected) def assert_amount(amount, expected_amount, expected_effective_amount): subscription.amount = amount json_data = subscription_adapter(subscription, self.dummy_request) self.assertEqual(json_data['amount'], expected_amount) self.assertEqual(json_data['effective_amount'], expected_effective_amount) assert_amount(None, None, subscription.plan.amount) assert_amount(1234, 1234, 1234) def assert_canceled_at(canceled_at, expected_canceled_at): subscription.canceled_at = canceled_at json_data = subscription_adapter(subscription, self.dummy_request) self.assertEqual(json_data['canceled_at'], expected_canceled_at) now = utc_now() assert_canceled_at(None, None) assert_canceled_at(now, now.isoformat())
def test_callback_with_duplicate_event(self): now = utc_now() self._do_callback('EV_ID_1', 'succeeded', now) with self.assertRaises(DuplicateEventError): self._do_callback('EV_ID_1', 'succeeded', now)
def test_callback_with_other_company(self): with db_transaction.manager: other_company = self.company_model.create('MOCK_PROCESSOR_KEY') with self.assertRaises(InvalidCallbackPayload): self._do_callback('EVID', 'succeeded', utc_now(), other_company)
def test_create_subscription(self, debit_method): amount = 5566 funding_instrument_uri = 'MOCK_CARD_URI' appears_on_statement_as = 'hello baby' now = utc_now() now_iso = now.isoformat() # next week next_invoice_at = utc_datetime(2013, 8, 23) next_iso = next_invoice_at.isoformat() debit_method.return_value = dict( processor_uri='MOCK_DEBIT_URI', status=self.transaction_model.statuses.SUCCEEDED, ) res = self.testapp.post( '/v1/subscriptions', dict( customer_guid=self.customer.guid, plan_guid=self.plan.guid, amount=amount, funding_instrument_uri=funding_instrument_uri, appears_on_statement_as=appears_on_statement_as, ), extra_environ=dict(REMOTE_USER=self.api_key), status=200, ) self.failUnless('guid' in res.json) self.assertEqual(res.json['created_at'], now_iso) self.assertEqual(res.json['updated_at'], now_iso) self.assertEqual(res.json['canceled_at'], None) self.assertEqual(res.json['next_invoice_at'], next_iso) self.assertEqual(res.json['invoice_count'], 1) self.assertEqual(res.json['amount'], amount) self.assertEqual(res.json['effective_amount'], amount) self.assertEqual(res.json['customer_guid'], self.customer.guid) self.assertEqual(res.json['plan_guid'], self.plan.guid) self.assertEqual(res.json['funding_instrument_uri'], funding_instrument_uri) self.assertEqual(res.json['appears_on_statement_as'], appears_on_statement_as) self.assertEqual(res.json['canceled'], False) subscription = self.subscription_model.get(res.json['guid']) self.assertEqual(subscription.invoice_count, 1) invoice = subscription.invoices[0] self.assertEqual(len(invoice.transactions), 1) self.assertEqual(invoice.amount, amount) self.assertEqual(invoice.scheduled_at, now) self.assertEqual(invoice.transaction_type, self.invoice_model.transaction_types.DEBIT) self.assertEqual(invoice.invoice_type, self.invoice_model.types.SUBSCRIPTION) self.assertEqual(invoice.appears_on_statement_as, appears_on_statement_as) transaction = invoice.transactions[0] debit_method.assert_called_once_with(transaction) self.assertEqual(transaction.processor_uri, 'MOCK_DEBIT_URI') self.assertEqual(transaction.submit_status, self.transaction_model.submit_statuses.DONE) self.assertEqual(transaction.appears_on_statement_as, subscription.appears_on_statement_as) self.assertEqual(transaction.amount, amount) self.assertEqual(transaction.transaction_type, self.transaction_model.types.DEBIT)
def test_callback_with_other_company(self): with db_transaction.manager: other_company = self.company_model.create('MOCK_PROCESSOR_KEY') with self.assertRaises(InvalidCallbackPayload): self._do_callback('EVID', 'succeeded', utc_now(), other_company)
def setUp(self): super(TestRenderer, self).setUp() with db_transaction.manager: self.company = self.company_model.create( processor_key='MOCK_PROCESSOR_KEY', ) self.customer = self.customer_model.create(company=self.company) self.plan = self.plan_model.create( company=self.company, frequency=self.plan_model.frequencies.WEEKLY, plan_type=self.plan_model.types.DEBIT, amount=1234, ) self.subscription = self.subscription_model.create( customer=self.customer, plan=self.plan, appears_on_statement_as='hello baby', ) self.customer_invoice = self.invoice_model.create( customer=self.customer, amount=7788, title='foobar invoice', external_id='external ID', appears_on_statement_as='hello baby', items=[ dict(type='debit', name='foo', amount=123, volume=5678), dict(name='bar', amount=456, quantity=10, unit='hours', volume=7788), ], adjustments=[ dict(amount=20, reason='A Lannister always pays his debts!'), dict(amount=3), ], ) self.subscription_invoice = self.invoice_model.create( subscription=self.subscription, amount=7788, title='foobar invoice', external_id='external ID2', appears_on_statement_as='hello baby', items=[ dict(type='debit', name='foo', amount=123, volume=5678), dict(name='bar', amount=456, quantity=10, unit='hours', volume=7788), ], adjustments=[ dict(amount=20, reason='A Lannister always pays his debts!'), dict(amount=3), ], scheduled_at=utc_now(), ) self.transaction = self.transaction_model.create( invoice=self.customer_invoice, transaction_type=self.transaction_model.types.DEBIT, amount=5678, funding_instrument_uri='/v1/cards/tester', appears_on_statement_as='hello baby', ) self.transaction_failure1 = self.transaction_failure_model.create( transaction=self.transaction, error_message='boom!', error_number=666, error_code='damin-it', ) with freeze_time('2013-08-17'): self.transaction_failure2 = self.transaction_failure_model.create( transaction=self.transaction, error_message='doomed!', error_number=777, error_code='screw-it', )
def test_callback_with_duplicate_event(self): now = utc_now() self._do_callback('EV_ID_1', 'succeeded', now) with self.assertRaises(DuplicateEventError): self._do_callback('EV_ID_1', 'succeeded', now)
def test_create_subscription(self, debit_method): amount = 5566 funding_instrument_uri = 'MOCK_CARD_URI' appears_on_statement_as = 'hello baby' now = utc_now() now_iso = now.isoformat() # next week next_invoice_at = utc_datetime(2013, 8, 23) next_iso = next_invoice_at.isoformat() debit_method.return_value = dict( processor_uri='MOCK_DEBIT_URI', status=self.transaction_model.statuses.SUCCEEDED, ) res = self.testapp.post( '/v1/subscriptions', dict( customer_guid=self.customer.guid, plan_guid=self.plan.guid, amount=amount, funding_instrument_uri=funding_instrument_uri, appears_on_statement_as=appears_on_statement_as, ), extra_environ=dict(REMOTE_USER=self.api_key), status=200, ) self.failUnless('guid' in res.json) self.assertEqual(res.json['created_at'], now_iso) self.assertEqual(res.json['updated_at'], now_iso) self.assertEqual(res.json['canceled_at'], None) self.assertEqual(res.json['next_invoice_at'], next_iso) self.assertEqual(res.json['invoice_count'], 1) self.assertEqual(res.json['amount'], amount) self.assertEqual(res.json['effective_amount'], amount) self.assertEqual(res.json['customer_guid'], self.customer.guid) self.assertEqual(res.json['plan_guid'], self.plan.guid) self.assertEqual(res.json['funding_instrument_uri'], funding_instrument_uri) self.assertEqual(res.json['appears_on_statement_as'], appears_on_statement_as) self.assertEqual(res.json['canceled'], False) subscription = self.subscription_model.get(res.json['guid']) self.assertEqual(subscription.invoice_count, 1) invoice = subscription.invoices[0] self.assertEqual(len(invoice.transactions), 1) self.assertEqual(invoice.amount, amount) self.assertEqual(invoice.scheduled_at, now) self.assertEqual(invoice.transaction_type, self.invoice_model.transaction_types.DEBIT) self.assertEqual(invoice.invoice_type, self.invoice_model.types.SUBSCRIPTION) self.assertEqual(invoice.appears_on_statement_as, appears_on_statement_as) transaction = invoice.transactions[0] debit_method.assert_called_once_with(transaction) self.assertEqual(transaction.processor_uri, 'MOCK_DEBIT_URI') self.assertEqual(transaction.submit_status, self.transaction_model.submit_statuses.DONE) self.assertEqual(transaction.appears_on_statement_as, subscription.appears_on_statement_as) self.assertEqual(transaction.amount, amount) self.assertEqual(transaction.transaction_type, self.transaction_model.types.DEBIT)
def setUp(self): super(TestRenderer, self).setUp() with db_transaction.manager: self.company = self.company_model.create( processor_key='MOCK_PROCESSOR_KEY', ) self.customer = self.customer_model.create( company=self.company ) self.plan = self.plan_model.create( company=self.company, frequency=self.plan_model.frequencies.WEEKLY, plan_type=self.plan_model.types.DEBIT, amount=1234, ) self.subscription = self.subscription_model.create( customer=self.customer, plan=self.plan, appears_on_statement_as='hello baby', ) self.customer_invoice = self.invoice_model.create( customer=self.customer, amount=7788, title='foobar invoice', external_id='external ID', appears_on_statement_as='hello baby', items=[ dict(type='debit', name='foo', amount=123, volume=5678), dict(name='bar', amount=456, quantity=10, unit='hours', volume=7788), ], adjustments=[ dict(amount=20, reason='A Lannister always pays his debts!'), dict(amount=3), ], ) self.subscription_invoice = self.invoice_model.create( subscription=self.subscription, amount=7788, title='foobar invoice', external_id='external ID2', appears_on_statement_as='hello baby', items=[ dict(type='debit', name='foo', amount=123, volume=5678), dict(name='bar', amount=456, quantity=10, unit='hours', volume=7788), ], adjustments=[ dict(amount=20, reason='A Lannister always pays his debts!'), dict(amount=3), ], scheduled_at=utc_now(), ) self.transaction = self.transaction_model.create( invoice=self.customer_invoice, transaction_type=self.transaction_model.types.DEBIT, amount=5678, funding_instrument_uri='/v1/cards/tester', appears_on_statement_as='hello baby', ) self.transaction_failure1 = self.transaction_failure_model.create( transaction=self.transaction, error_message='boom!', error_number=666, error_code='damin-it', ) with freeze_time('2013-08-17'): self.transaction_failure2 = self.transaction_failure_model.create( transaction=self.transaction, error_message='doomed!', error_number=777, error_code='screw-it', )