class CardRewardTest(TestCase): """ Test case for the ``CardRewardView`` API view. Rewards must be performed by following this schema: 1 - The business transfers the reward amount to the consumer. 2 - A fixed percentage (by default the 40%) of that amount is deducted for the consumer cause. 3 - The consumer transfers that percentage of the reward amount to the cause. Then, two transactions must be performed and also logged to the system. """ @skipIf(not 'cc3.rewards' in settings.INSTALLED_APPS, u'Skipped as cc3.rewards app not enabled') def setUp(self): self.backend = DummyCyclosBackend() set_backend(self.backend) self.group_1 = CyclosGroupFactory.create(initial=True) self.groupset = CyclosGroupSetFactory.create( groups=[self.group_1, ]) self.community = CC3CommunityFactory.create( groupsets=[self.groupset], code='TST') # Create business with its terminal. self.user_1 = UserFactory.create() self.terminal_1 = TerminalFactory.create(business=self.user_1) self.token_1 = Token.objects.create(user=self.user_1) self.operator_1 = OperatorFactory(business=self.user_1) self.cc3profile_1 = CC3ProfileFactory.create( user=self.user_1, first_name='Test', last_name='Business', community=self.community, cyclos_group=self.group_1) self.business_settings = BusinessCauseSettingsFactory.create( user=self.user_1) # Create card users. self.user_2 = UserFactory.create() self.cc3profile_2 = CC3ProfileFactory.create( user=self.user_2, first_name='Test', last_name='User', community=self.community, cyclos_group=self.group_1) self.user_cause = UserCauseFactory.create(consumer=self.user_2) self.community_2 = CC3CommunityFactory.create( groupsets=[self.groupset], code='TST') self.user_3 = UserFactory.create() self.cc3profile_3 = CC3ProfileFactory.create( user=self.user_3, first_name='Test', last_name='User', community=self.community_2, cyclos_group=self.group_1) self.user_4 = UserFactory.create() self.terminal_4 = TerminalFactory.create(business=self.user_4) self.token_4 = Token.objects.create(user=self.user_4) self.operator_4 = OperatorFactory(business=self.user_4) self.client = self.client_class(HTTP_AUTHORIZATION='Token {0}'.format( self.token_1.key)) self.card_2 = CardFactory.create(owner=self.user_2) self.card_3 = CardFactory.create(owner=self.user_3) self.url = reverse( 'api_cards_card_reward', args=[self.card_2.number.uid_number]) self.post_data = { 'terminal_name': self.terminal_1.name, 'operator_name': self.operator_1.name, 'sender_id': self.operator_1.business.id, 'receiver_id': self.card_2.owner.id, 'amount': '100', 'description': 'Reward to good cause {0}'.format( self.user_cause.cause) } @skipIf(not 'cc3.rewards' in settings.INSTALLED_APPS, u'Skipped as cc3.rewards app not enabled') @override_settings(INTER_COMMUNITIES_TRANSACTIONS=True) def test_card_reward_business_to_consumer_transaction(self): """ Tests the transaction from business to consumer performed during a successful reward operation. """ response = self.client.post( self.url, data=json.dumps(self.post_data), content_type='application/json') self.assertEqual(response.status_code, HTTP_200_OK) data = json.loads(response.content) self.assertEqual(data['card_transaction_id'], self.backend.transactions()[0].transfer_id) # Check the transaction from business to consumer. trans = self.backend.transactions()[0] self.assertEqual(trans.amount, 100) self.assertEqual(trans.sender, self.terminal_1.business) self.assertEqual(trans.recipient, self.card_2.owner) self.assertEqual(trans.description, self.post_data['description']) @skipIf(not 'cc3.rewards' in settings.INSTALLED_APPS, u'Skipped as cc3.rewards app not enabled') @override_settings(INTER_COMMUNITIES_TRANSACTIONS=True) def test_card_reward_consumer_to_cause_transaction(self): """ Tests the transaction from consumer to cause performed during a successful reward operation. """ response = self.client.post( self.url, data=json.dumps(self.post_data), content_type='application/json') self.assertEqual(response.status_code, HTTP_200_OK) data = json.loads(response.content) self.assertEqual(data['reward_transaction_id'], self.backend.transactions()[1].transfer_id) # Check the transaction from consumer to cause. # It must be the 40% of the initial transaction. trans = self.backend.transactions()[1] self.assertEqual(trans.amount, 40) self.assertEqual(trans.sender, self.card_2.owner) self.assertEqual(trans.recipient, self.user_cause.cause) self.assertEqual(trans.description, _('Cause donation')) @skipIf(not 'cc3.rewards' in settings.INSTALLED_APPS, u'Skipped as cc3.rewards app not enabled') @override_settings(INTER_COMMUNITIES_TRANSACTIONS=True) def test_card_reward_transaction_logged(self): """ Tests the creation of ``Transaction`` objects to log the rewarding. There must be 2 ``Transaction``s logged: one from the business to the consumer and another one from the consumer to the cause. """ response = self.client.post( self.url, data=json.dumps(self.post_data), content_type='application/json') self.assertEqual(response.status_code, HTTP_200_OK) transactions = CardTransaction.objects.all() self.assertEqual(len(transactions), 2) @skipIf(not 'cc3.rewards' in settings.INSTALLED_APPS, u'Skipped as cc3.rewards app not enabled') @override_settings(INTER_COMMUNITIES_TRANSACTIONS=True) def test_card_reward_invalid_terminal(self): """ Test wrong terminal name when performing a reward """ self.post_data['terminal_name'] = 'invalid' response = self.client.post( self.url, data=json.dumps(self.post_data), content_type='application/json') self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST) @skipIf(not 'cc3.rewards' in settings.INSTALLED_APPS, u'Skipped as cc3.rewards app not enabled') @override_settings(INTER_COMMUNITIES_TRANSACTIONS=True) def test_card_reward_invalid_operator(self): """ Test wrong operator name when performing a reward """ self.post_data['operator_name'] = 'invalid' response = self.client.post( self.url, data=json.dumps(self.post_data), content_type='application/json') self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST) # TODO, test to check community and user values are used appropriately #@override_settings(INTER_COMMUNITIES_TRANSACTIONS=True, # REWARDS_FIXED_PERCENTAGE=None) #@skipIf(not 'cc3.rewards' in settings.INSTALLED_APPS, # u'Skipped as cc3.rewards app not enabled') #def test_card_reward_fixed_percentage_setting(self): # """ # Test automatic fallback when ``REWARDS_FIXED_PERCENTAGE`` setting is # missing. # """ # # Delete the setting. # del settings.REWARDS_FIXED_PERCENTAGE # # response = self.client.post( # self.url, data=json.dumps(self.post_data), # content_type='application/json') # # self.assertEqual(response.status_code, HTTP_200_OK) # # data = json.loads(response.content) # # self.assertEqual(data['reward_transaction_id'], # self.backend.transactions()[1].transfer_id) # # # Check the transaction from consumer to cause. # # It must be the 40% of the initial transaction. # trans = self.backend.transactions()[1] # self.assertEqual(trans.amount, 40) # self.assertEqual(trans.sender, self.card_2.owner) # self.assertEqual(trans.recipient, self.user_cause.cause) # self.assertEqual(trans.description, _('Cause donation')) @skipIf(not 'cc3.rewards' in settings.INSTALLED_APPS, u'Skipped as cc3.rewards app not enabled') @override_settings(INTER_COMMUNITIES_TRANSACTIONS=True) def test_card_reward_no_cause_available(self): """ Tests that the request returns a 400 error when the user has no charity cause configured. """ url = reverse( 'api_cards_card_reward', args=[self.card_3.number.uid_number]) post_data = { 'terminal_name': self.terminal_1.name, 'operator_name': self.operator_1.name, 'sender_id': self.operator_1.business.id, 'receiver_id': self.card_3.owner.id, 'amount': '100', 'description': 'Reward to good cause {0}'.format( self.user_cause.cause) } response = self.client.post( url, data=json.dumps(post_data), content_type='application/json') self.assertEqual(response.status_code, HTTP_200_OK) data = json.loads(response.content) self.assertIsNone(data['reward_transaction_id']) @skipIf(not 'cc3.rewards' in settings.INSTALLED_APPS, u'Skipped as cc3.rewards app not enabled') @override_settings(INTER_COMMUNITIES_TRANSACTIONS=False) def test_card_reward_inter_community_fails(self): """ Tests that the request returns a 400 error when the reward is attempted to a business and/or cause in a different community. NB this relies on the fact that all users in these tests are in different communities """ url = reverse( 'api_cards_card_reward', args=[self.card_3.number.uid_number]) post_data = { 'terminal_name': self.terminal_1.name, 'operator_name': self.operator_1.name, 'sender_id': self.operator_1.business.id, 'receiver_id': self.card_3.owner.id, 'amount': '100', 'description': 'Reward to good cause {0}'.format( self.user_cause.cause) } response = self.client.post( url, data=json.dumps(post_data), content_type='application/json') self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST)
class CardPaymentTest(TestCase): def setUp(self): self.backend = DummyCyclosBackend() set_backend(self.backend) self.group_1 = CyclosGroupFactory.create(initial=True) self.groupset = CyclosGroupSetFactory.create( groups=[self.group_1, ]) self.community = CC3CommunityFactory.create( groupsets=[self.groupset], code='TST') self.user_1 = UserFactory.create() self.terminal_1 = TerminalFactory.create(business=self.user_1) self.token_1 = Token.objects.create(user=self.user_1) self.operator_1 = OperatorFactory(business=self.user_1) self.cc3profile_1 = CC3ProfileFactory.create( user=self.user_1, first_name='Test', last_name='Business', community=self.community, cyclos_group=self.group_1) self.user_2 = UserFactory.create() self.cc3profile_2 = CC3ProfileFactory.create( user=self.user_2, first_name='Test', last_name='User', community=self.community, cyclos_group=self.group_1) self.user_3 = UserFactory.create() self.user_4 = UserFactory.create() self.terminal_4 = TerminalFactory.create(business=self.user_4) self.token_4 = Token.objects.create(user=self.user_4) self.operator_4 = OperatorFactory(business=self.user_4) self.client = self.client_class(HTTP_AUTHORIZATION='Token {0}'.format( self.token_1.key)) self.card_2 = CardFactory.create(owner=self.user_2) self.card_3 = CardFactory.create(owner=self.user_3) self.community_5 = CC3CommunityFactory.create( groupsets=[self.groupset]) self.user_5 = UserFactory.create() self.cc3profile_5 = CC3ProfileFactory.create( user=self.user_5, first_name='Test', last_name='User5', community=self.community_5, cyclos_group=self.group_1) self.card_5 = CardFactory.create(owner=self.user_5) self.blocked_card = CardFactory.create(owner=self.user_2) self.blocked_card.block_card() self.url = reverse( 'api_cards_card_payment', args=[self.card_2.number.uid_number]) def test_card_pay_successful(self): """ Test a payment from a user/card-holder to the business owner """ data = { 'terminal_name': self.terminal_1.name, 'operator_name': self.operator_1.name, 'sender_id': self.card_2.owner.id, 'receiver_id': self.operator_1.business.id, 'amount': '50', 'description': 'My transaction' } response = self.client.post( self.url, data=json.dumps(data), content_type='application/json') self.assertEqual(response.status_code, HTTP_200_OK) data = json.loads(response.content) self.assertEqual(data['transaction_id'], self.backend.transactions()[0].transfer_id) trans = self.backend.transactions()[0] self.assertEqual(trans.amount, 50) self.assertEqual(trans.sender, self.card_2.owner) self.assertEqual(trans.recipient, self.operator_1.business) self.assertEqual(trans.description, 'My transaction') def test_card_pay_successful_decimal(self): """ Test a decimal payment from a user/card-holder to business owner """ data = { 'terminal_name': self.terminal_1.name, 'operator_name': self.operator_1.name, 'sender_id': self.card_2.owner.id, 'receiver_id': self.operator_1.business.id, 'amount': '40.01', 'description': 'My transaction' } response = self.client.post( self.url, data=json.dumps(data), content_type='application/json') self.assertEqual(response.status_code, HTTP_200_OK) data = json.loads(response.content) self.assertEqual(data['transaction_id'], self.backend.transactions()[0].transfer_id) trans = self.backend.transactions()[0] self.assertEqual(trans.amount, Decimal('40.01')) self.assertEqual(trans.sender, self.card_2.owner) self.assertEqual(trans.recipient, self.operator_1.business) self.assertEqual(trans.description, 'My transaction') def test_card_payment_operator_name_business_unique_together(self): """ Test a payment operation when there is more than one ``Operator`` object with the same ``name`` defined. Enforces the checkup of the 'unique together' relationship of the two fields in the ``Operator`` model, which is used in the API view ``CardTransactionView`` to retrieve the operator. """ OperatorFactory(name=self.operator_1.name) data = { 'terminal_name': self.terminal_1.name, 'operator_name': self.operator_1.name, 'sender_id': self.card_2.owner.id, 'receiver_id': self.operator_1.business.id, 'amount': '50', 'description': 'My transaction' } response = self.client.post( self.url, data=json.dumps(data), content_type='application/json') self.assertEqual(response.status_code, HTTP_200_OK) def test_card_receive(self): """ Test a payment from the business owner to the user/card-holder """ data = { 'terminal_name': self.terminal_1.name, 'operator_name': self.operator_1.name, 'receiver_id': self.card_2.owner.id, 'sender_id': self.operator_1.business.id, 'amount': '50', 'description': 'My transaction' } response = self.client.post( self.url, data=json.dumps(data), content_type='application/json') self.assertEqual(response.status_code, HTTP_200_OK) data = json.loads(response.content) self.assertEqual(data['transaction_id'], self.backend.transactions()[0].transfer_id) trans = self.backend.transactions()[0] self.assertEqual(trans.amount, 50) self.assertEqual(trans.recipient, self.card_2.owner) self.assertEqual(trans.sender, self.operator_1.business) self.assertEqual(trans.description, 'My transaction') def test_card_receive_credit_limit(self): """ Test a payment from the business owner to the user/card-holder, where the balance of the business owner can become negative (DummyCyclosBackend credit limit: 50) """ data = { 'terminal_name': self.terminal_1.name, 'operator_name': self.operator_1.name, 'receiver_id': self.card_2.owner.id, 'sender_id': self.operator_1.business.id, 'amount': '149', 'description': 'My transaction' } response = self.client.post( self.url, data=json.dumps(data), content_type='application/json') self.assertEqual(response.status_code, HTTP_200_OK) data = json.loads(response.content) self.assertEqual(data['transaction_id'], self.backend.transactions()[0].transfer_id) trans = self.backend.transactions()[0] self.assertEqual(trans.amount, 149) self.assertEqual(trans.recipient, self.card_2.owner) self.assertEqual(trans.sender, self.operator_1.business) self.assertEqual(trans.description, 'My transaction') def test_card_receive_credit_limit_invalid(self): """ Test a payment from the business owner to the user/card-holder, where the credit limit of the business owner is invalid. (DummyCyclosBackend credit limit: 50) """ data = { 'terminal_name': self.terminal_1.name, 'operator_name': self.operator_1.name, 'receiver_id': self.card_2.owner.id, 'sender_id': self.operator_1.business.id, 'amount': '151', 'description': 'My transaction' } response = self.client.post( self.url, data=json.dumps(data), content_type='application/json') self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST) def test_card_pay_invalid_terminal(self): """ Wrong terminal name """ data = { 'terminal_name': 'invalid', 'operator_name': self.operator_1.name, 'sender_id': self.card_2.owner.id, 'receiver_id': self.operator_1.business.id, 'amount': '50', 'description': 'My transaction' } response = self.client.post( self.url, data=json.dumps(data), content_type='application/json') self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST) def test_card_pay_invalid_operator(self): """ Wrong operator name """ data = { 'terminal_name': self.terminal_1.name, 'operator_name': 'invalid', 'sender_id': self.card_2.owner.id, 'receiver_id': self.operator_1.business.id, 'amount': '50', 'description': 'My transaction' } response = self.client.post( self.url, data=json.dumps(data), content_type='application/json') self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST) def test_card_pay_third_party_payment(self): """ Unable to perform payments if we're not one of either party. Note that we authenticate with terminal_1/operator_1 """ data = { 'terminal_name': self.terminal_4.name, 'operator_name': self.operator_4.name, 'sender_id': self.card_2.owner.id, 'receiver_id': self.operator_4.business.id, 'amount': '50', 'description': 'My transaction' } response = self.client.post( self.url, data=json.dumps(data), content_type='application/json') self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST) def test_card_pay_same_sender_receiver(self): """ Can't send payments if the user is both sender and receiver """ data = { 'terminal_name': self.terminal_1.name, 'operator_name': self.operator_1.name, 'sender_id': self.card_2.owner.id, 'receiver_id': self.card_2.owner.id, 'amount': '50', 'description': 'My transaction' } response = self.client.post( self.url, data=json.dumps(data), content_type='application/json') self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST) def test_card_pay_wrong_card(self): """ The payment must be made on the correct card resource """ data = { 'terminal_name': self.terminal_1.name, 'operator_name': self.operator_1.name, 'sender_id': self.card_3.owner.id, 'receiver_id': self.operator_1.business.id, 'amount': '50', 'description': 'My transaction' } response = self.client.post( self.url, data=json.dumps(data), content_type='application/json') self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST) def test_card_pay_from_blocked_card(self): """ The payment must be from a non-blocked card """ data = { 'terminal_name': self.terminal_1.name, 'operator_name': self.operator_1.name, 'sender_id': self.blocked_card.owner.id, 'receiver_id': self.card_2.owner.id, 'amount': '50', 'description': 'My transaction' } url = reverse( 'api_cards_card_payment', args=[self.blocked_card.number.uid_number]) response = self.client.post( self.url, data=json.dumps(data), content_type='application/json') self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST) @override_settings(INTER_COMMUNITIES_TRANSACTIONS=False) def test_card_pay_inter_community_not_possible(self): """ Testing INTER_COMMUNITIES_TRANSACTIONS=False blocks """ data = { 'terminal_name': self.terminal_1.name, 'operator_name': self.operator_1.name, 'sender_id': self.card_5.owner.id, 'receiver_id': self.operator_1.business.id, 'amount': '50', 'description': 'My transaction' } response = self.client.post( self.url, data=json.dumps(data), content_type='application/json') self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST) @override_settings(INTER_COMMUNITIES_TRANSACTIONS=True) def test_card_pay_inter_community_possible(self): """ Testing INTER_COMMUNITIES_TRANSACTIONS=True allows """ data = { 'terminal_name': self.terminal_1.name, 'operator_name': self.operator_1.name, 'sender_id': self.card_2.owner.id, 'receiver_id': self.operator_1.business.id, 'amount': '50', 'description': 'My transaction' } response = self.client.post( self.url, data=json.dumps(data), content_type='application/json') self.assertEqual(response.status_code, HTTP_200_OK)