from django.test import TestCase from django.contrib.auth import get_user_model from datetime import datetime, date, timedelta from .models import * from uncloud_service.models import GenericServiceProduct class ProductTestCase(TestCase): """ Test products and products <-> order interaction """ def setUp(self): self.user = get_user_model().objects.create( username='random_user', email='jane.random@domain.tld') ba = BillingAddress.objects.create( owner=self.user, organization = 'Test org', street="unknown", city="unknown", postal_code="somewhere else", active=True) def test_create_one_time_product(self): """ One time payment products cannot be updated - can they? """ p = SampleOneTimeProduct.objects.create(owner=self.user) self.assertEqual(p.one_time_price, 5) self.assertEqual(p.recurring_price, 0) def test_create_order_creates_correct_order_count(self): """ Ensure creating orders from product only creates 1 order """ # One order p = SampleOneTimeProduct.objects.create(owner=self.user) p.create_order_at(timezone.make_aware(datetime.datetime(2020,3,3))) order_count = Order.objects.filter(owner=self.user).count() self.assertEqual(order_count, 1) # One more order p = SampleRecurringProduct.objects.create(owner=self.user) p.create_order_at(timezone.make_aware(datetime.datetime(2020,3,3))) order_count = Order.objects.filter(owner=self.user).count() self.assertEqual(order_count, 2) # Should create 2 orders p = SampleRecurringProductOneTimeFee.objects.create(owner=self.user) p.create_order_at(timezone.make_aware(datetime.datetime(2020,3,3))) order_count = Order.objects.filter(owner=self.user).count() self.assertEqual(order_count, 4) class BillingAddressTestCase(TestCase): def setUp(self): self.user = get_user_model().objects.create( username='random_user', email='jane.random@domain.tld') def test_user_no_address(self): """ Raise an error, when there is no address """ self.assertRaises(uncloud_pay.models.BillingAddress.DoesNotExist, BillingAddress.get_address_for, self.user) def test_user_only_inactive_address(self): """ Raise an error, when there is no active address """ ba = BillingAddress.objects.create( owner=self.user, organization = 'Test org', street="unknown", city="unknown", postal_code="somewhere else", active=False) self.assertRaises(uncloud_pay.models.BillingAddress.DoesNotExist, BillingAddress.get_address_for, self.user) def test_find_active_address(self): """ Find the active address """ ba = BillingAddress.objects.create( owner=self.user, organization = 'Test org', street="unknown", city="unknown", postal_code="unknown", active=True) self.assertEqual(BillingAddress.get_address_for(self.user), ba) def test_find_right_address_with_multiple_addresses(self): """ Find the active address only, skip inactive """ ba = BillingAddress.objects.create( owner=self.user, organization = 'Test org', street="unknown", city="unknown", postal_code="unknown", active=True) ba2 = BillingAddress.objects.create( owner=self.user, organization = 'Test org', street="unknown", city="unknown", postal_code="somewhere else", active=False) self.assertEqual(BillingAddress.get_address_for(self.user), ba) def test_change_addresses(self): """ Switch the active address """ ba = BillingAddress.objects.create( owner=self.user, organization = 'Test org', street="unknown", city="unknown", postal_code="unknown", active=True) self.assertEqual(BillingAddress.get_address_for(self.user), ba) ba.active=False ba.save() ba2 = BillingAddress.objects.create( owner=self.user, organization = 'Test org', street="unknown", city="unknown", postal_code="somewhere else", active=True) self.assertEqual(BillingAddress.get_address_for(self.user), ba2) class BillTestCase(TestCase): def setUp(self): self.user_without_address = get_user_model().objects.create( username='no_home_person', email='far.away@domain.tld') self.user = get_user_model().objects.create( username='jdoe', email='john.doe@domain.tld') self.recurring_user = get_user_model().objects.create( username='recurrent_product_user', email='jane.doe@domain.tld') self.user_addr = BillingAddress.objects.create( owner=self.user, organization = 'Test org', street="unknown", city="unknown", postal_code="unknown", active=True) self.recurring_user_addr = BillingAddress.objects.create( owner=self.recurring_user, organization = 'Test org', street="Somewhere", city="Else", postal_code="unknown", active=True) self.order_meta = {} self.order_meta[1] = { 'starting_date': timezone.make_aware(datetime.datetime(2020,3,3)), 'ending_date': timezone.make_aware(datetime.datetime(2020,4,17)), 'price': 15, 'description': 'One chocolate bar' } self.one_time_order = Order.objects.create( owner=self.user, starting_date=self.order_meta[1]['starting_date'], ending_date=self.order_meta[1]['ending_date'], recurring_period=RecurringPeriod.ONE_TIME, price=self.order_meta[1]['price'], description=self.order_meta[1]['description'], billing_address=BillingAddress.get_address_for(self.user)) self.recurring_order = Order.objects.create( owner=self.recurring_user, starting_date=timezone.make_aware(datetime.datetime(2020,3,3)), recurring_period=RecurringPeriod.PER_30D, price=15, description="A pretty VM", billing_address=BillingAddress.get_address_for(self.recurring_user) ) # used for generating multiple bills self.bill_dates = [ timezone.make_aware(datetime.datetime(2020,3,31)), timezone.make_aware(datetime.datetime(2020,4,30)), timezone.make_aware(datetime.datetime(2020,5,31)), ] def test_bill_one_time_one_bill_record(self): """ Ensure there is only 1 bill record per order """ bill = Bill.create_next_bill_for_user_address(self.user, self.user_addr) self.assertEqual(self.one_time_order.billrecord_set.count(), 1) def test_bill_sum_onetime(self): """ Check the bill sum for a single one time order """ bill = Bill.create_next_bill_for_user_address(self.user, self.user_addr) self.assertEqual(bill.sum, self.order_meta[1]['price']) def test_bill_creates_record_for_recurring_order(self): """ Ensure there is only 1 bill record per order """ bill = Bill.create_next_bill_for_user_address(self.recurring_user, self.recurring_user_addr) self.assertEqual(self.recurring_order.billrecord_set.count(), 1) self.assertEqual(bill.billrecord_set.count(), 1) def test_new_bill_after_closing(self): """ After closing a bill and the user has a recurring product, the next bill run should create e new bill """ for ending_date in self.bill_dates: b = Bill.create_next_bill_for_user_address(self.recurring_user, self.recurring_user_addr, ending_date) b.close() bill_count = Bill.objects.filter(owner=self.recurring_user).count() self.assertEqual(len(self.bill_dates), bill_count) def test_multi_addr_multi_bill(self): """ Ensure multiple bills are created if orders exist with different billing addresses """ username="lotsofplaces" multi_addr_user = get_user_model().objects.create( username=username, email=f"{username}@example.org") user_addr1 = BillingAddress.objects.create( owner=multi_addr_user, organization = 'Test org', street="unknown", city="unknown", postal_code="unknown", active=True) order1 = Order.objects.create( owner=multi_addr_user, starting_date=self.order_meta[1]['starting_date'], ending_date=self.order_meta[1]['ending_date'], recurring_period=RecurringPeriod.ONE_TIME, price=self.order_meta[1]['price'], description=self.order_meta[1]['description'], billing_address=BillingAddress.get_address_for(self.user)) # Make this address inactive user_addr1.active = False user_addr1.save() user_addr2 = BillingAddress.objects.create( owner=multi_addr_user, organization = 'Test2 org', street="unknown2", city="unknown2", postal_code="unknown2", active=True) order2 = Order.objects.create( owner=multi_addr_user, starting_date=self.order_meta[1]['starting_date'], ending_date=self.order_meta[1]['ending_date'], recurring_period=RecurringPeriod.ONE_TIME, price=self.order_meta[1]['price'], description=self.order_meta[1]['description'], billing_address=BillingAddress.get_address_for(self.user)) bills = Bill.create_next_bills_for_user(multi_addr_user) self.assertEqual(len(bills), 2) class ModifyProductTestCase(TestCase): def setUp(self): self.user = get_user_model().objects.create( username='random_user', email='jane.random@domain.tld') self.ba = BillingAddress.objects.create( owner=self.user, organization = 'Test org', street="unknown", city="unknown", postal_code="somewhere else", active=False) def test_user_no_address(self): """ Raise an error, when there is no address """ self.assertRaises(uncloud_pay.models.BillingAddress.DoesNotExist, BillingAddress.get_address_for, self.user) def test_user_only_inactive_address(self): """ Raise an error, when there is no active address """ # class NotABillingTC(TestCase): # #class BillingTestCase(TestCase): # def setUp(self): # self.user = get_user_model().objects.create( # username='jdoe', # email='john.doe@domain.tld') # self.billing_address = BillingAddress.objects.create( # owner=self.user, # street="unknown", # city="unknown", # postal_code="unknown") # def test_basic_monthly_billing(self): # one_time_price = 10 # recurring_price = 20 # description = "Test Product 1" # # Three months: full, full, partial. # # starting_date = datetime.fromisoformat('2020-03-01') # starting_date = datetime(2020,3,1) # ending_date = datetime(2020,5,8) # # Create order to be billed. # order = Order.objects.create( # owner=self.user, # starting_date=starting_date, # ending_date=ending_date, # recurring_period=RecurringPeriod.PER_30D, # recurring_price=recurring_price, # one_time_price=one_time_price, # description=description, # billing_address=self.billing_address) # # Generate & check bill for first month: full recurring_price + setup. # first_month_bills = order.generate_initial_bill() # self.assertEqual(len(first_month_bills), 1) # self.assertEqual(first_month_bills[0].amount, one_time_price + recurring_price) # # Generate & check bill for second month: full recurring_price. # second_month_bills = Bill.generate_for(2020, 4, self.user) # self.assertEqual(len(second_month_bills), 1) # self.assertEqual(second_month_bills[0].amount, recurring_price) # # Generate & check bill for third and last month: partial recurring_price. # third_month_bills = Bill.generate_for(2020, 5, self.user) # self.assertEqual(len(third_month_bills), 1) # # 31 days in May. # self.assertEqual(float(third_month_bills[0].amount), # round(round((7/31), AMOUNT_DECIMALS) * recurring_price, AMOUNT_DECIMALS)) # # Check that running Bill.generate_for() twice does not create duplicates. # self.assertEqual(len(Bill.generate_for(2020, 3, self.user)), 0) # def test_basic_yearly_billing(self): # one_time_price = 10 # recurring_price = 150 # description = "Test Product 1" # starting_date = datetime.fromisoformat('2020-03-31T08:05:23') # # Create order to be billed. # order = Order.objects.create( # owner=self.user, # starting_date=starting_date, # recurring_period=RecurringPeriod.PER_365D, # recurring_price=recurring_price, # one_time_price=one_time_price, # description=description, # billing_address=self.billing_address) # # Generate & check bill for first year: recurring_price + setup. # first_year_bills = order.generate_initial_bill() # self.assertEqual(len(first_year_bills), 1) # self.assertEqual(first_year_bills[0].starting_date.date(), # date.fromisoformat('2020-03-31')) # self.assertEqual(first_year_bills[0].ending_date.date(), # date.fromisoformat('2021-03-30')) # self.assertEqual(first_year_bills[0].amount, # recurring_price + one_time_price) # # Generate & check bill for second year: recurring_price. # second_year_bills = Bill.generate_for(2021, 3, self.user) # self.assertEqual(len(second_year_bills), 1) # self.assertEqual(second_year_bills[0].starting_date.date(), # date.fromisoformat('2021-03-31')) # self.assertEqual(second_year_bills[0].ending_date.date(), # date.fromisoformat('2022-03-30')) # self.assertEqual(second_year_bills[0].amount, recurring_price) # # Check that running Bill.generate_for() twice does not create duplicates. # self.assertEqual(len(Bill.generate_for(2020, 3, self.user)), 0) # self.assertEqual(len(Bill.generate_for(2020, 4, self.user)), 0) # self.assertEqual(len(Bill.generate_for(2020, 2, self.user)), 0) # self.assertEqual(len(Bill.generate_for(2021, 3, self.user)), 0) # def test_basic_hourly_billing(self): # one_time_price = 10 # recurring_price = 1.4 # description = "Test Product 1" # starting_date = datetime.fromisoformat('2020-03-31T08:05:23') # ending_date = datetime.fromisoformat('2020-04-01T11:13:32') # # Create order to be billed. # order = Order.objects.create( # owner=self.user, # starting_date=starting_date, # ending_date=ending_date, # recurring_period=RecurringPeriod.PER_HOUR, # recurring_price=recurring_price, # one_time_price=one_time_price, # description=description, # billing_address=self.billing_address) # # Generate & check bill for first month: recurring_price + setup. # first_month_bills = order.generate_initial_bill() # self.assertEqual(len(first_month_bills), 1) # self.assertEqual(float(first_month_bills[0].amount), # round(16 * recurring_price, AMOUNT_DECIMALS) + one_time_price) # # Generate & check bill for first month: recurring_price. # second_month_bills = Bill.generate_for(2020, 4, self.user) # self.assertEqual(len(second_month_bills), 1) # self.assertEqual(float(second_month_bills[0].amount), # round(12 * recurring_price, AMOUNT_DECIMALS)) # class ProductActivationTestCase(TestCase): # def setUp(self): # self.user = get_user_model().objects.create( # username='jdoe', # email='john.doe@domain.tld') # self.billing_address = BillingAddress.objects.create( # owner=self.user, # street="unknown", # city="unknown", # postal_code="unknown") # def test_product_activation(self): # starting_date = datetime.fromisoformat('2020-03-01') # one_time_price = 0 # recurring_price = 1 # description = "Test Product" # order = Order.objects.create( # owner=self.user, # starting_date=starting_date, # recurring_period=RecurringPeriod.PER_30D, # recurring_price=recurring_price, # one_time_price=one_time_price, # description=description, # billing_address=self.billing_address) # product = GenericServiceProduct( # custom_description=description, # custom_one_time_price=one_time_price, # custom_recurring_price=recurring_price, # owner=self.user, # order=order) # product.save() # # Validate initial state: must be awaiting payment. # self.assertEqual(product.status, UncloudStatus.AWAITING_PAYMENT) # # Pay initial bill, check that product is activated. # order.generate_initial_bill() # amount = product.order.bills[0].amount # payment = Payment(owner=self.user, amount=amount) # payment.save() # self.assertEqual( # GenericServiceProduct.objects.get(uuid=product.uuid).status, # UncloudStatus.PENDING # ) # class BillingAddressTestCase(TestCase): # def setUp(self): # self.user = get_user_model().objects.create( # username='jdoe', # email='john.doe@domain.tld') # self.billing_address_01 = BillingAddress.objects.create( # owner=self.user, # street="unknown1", # city="unknown1", # postal_code="unknown1", # country="CH") # self.billing_address_02 = BillingAddress.objects.create( # owner=self.user, # street="unknown2", # city="unknown2", # postal_code="unknown2", # country="CH") # def test_billing_with_single_address(self): # # Create new orders somewhere in the past so that we do not encounter # # auto-created initial bills. # starting_date = datetime.fromisoformat('2020-03-01') # order_01 = Order.objects.create( # owner=self.user, # starting_date=starting_date, # recurring_period=RecurringPeriod.PER_30D, # billing_address=self.billing_address_01) # order_02 = Order.objects.create( # owner=self.user, # starting_date=starting_date, # recurring_period=RecurringPeriod.PER_30D, # billing_address=self.billing_address_01) # # We need a single bill since we work with a single address. # bills = Bill.generate_for(2020, 4, self.user) # self.assertEqual(len(bills), 1) # def test_billing_with_multiple_addresses(self): # # Create new orders somewhere in the past so that we do not encounter # # auto-created initial bills. # starting_date = datetime.fromisoformat('2020-03-01') # order_01 = Order.objects.create( # owner=self.user, # starting_date=starting_date, # recurring_period=RecurringPeriod.PER_30D, # billing_address=self.billing_address_01) # order_02 = Order.objects.create( # owner=self.user, # starting_date=starting_date, # recurring_period=RecurringPeriod.PER_30D, # billing_address=self.billing_address_02) # # We need different bills since we work with different addresses. # bills = Bill.generate_for(2020, 4, self.user) # self.assertEqual(len(bills), 2)