├── .gitignore ├── red_line_promotion.py └── tests └── redline_tests.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | -------------------------------------------------------------------------------- /red_line_promotion.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | def red_pencil_promotion_started(from_price, to_price, todays_date=datetime.datetime.now(), last_price_change_date=datetime.datetime.min): 4 | time_delta_since_last_price_change = todays_date - last_price_change_date 5 | if time_delta_since_last_price_change.days > 30: 6 | return to_price/from_price <= 0.95 and to_price/from_price >= 0.7 7 | 8 | def reduce_price_of(original_price, by): 9 | return (1-by)*original_price 10 | 11 | class Good(): 12 | def __init__(self, price): 13 | self.price = price 14 | self.price_reduction_history = [] 15 | def reduce_price(self, by, effective=datetime.datetime.now()): 16 | current_price = self.get_price(effective) 17 | self.reduced_price = reduce_price_of(current_price, by=by) 18 | self.price_reduction_history.append((by, self.reduced_price, effective)) 19 | if len(self.price_reduction_history) == 1: 20 | return red_pencil_promotion_started(self.price, self.reduced_price, todays_date=effective) 21 | return red_pencil_promotion_started(self.price, self.reduced_price, todays_date=effective, last_price_change_date=self.price_reduction_history[0][2]) 22 | def is_redline_promotion_effective_now(self): 23 | return red_pencil_promotion_started(self.price, self.reduced_price) 24 | def get_price(self, effective): 25 | most_recent_price_found = self.price 26 | for item in self.price_reduction_history: 27 | if item[2] <= effective: 28 | most_recent_price_found = item[1] 29 | else: 30 | break 31 | return most_recent_price_found 32 | -------------------------------------------------------------------------------- /tests/redline_tests.py: -------------------------------------------------------------------------------- 1 | import unittest, datetime 2 | from red_line_promotion import * 3 | 4 | def always_passing_test(): 5 | assert True 6 | 7 | class given_a_good_with_no_price_change_ever(unittest.TestCase): 8 | def setUp(self): 9 | self.good = Good(price = 100.00) 10 | def test_when_price_is_changed_to_same_price(self): 11 | self.good.reduce_price(by=0.0) 12 | self.assertFalse(self.good.is_redline_promotion_effective_now(), "It should not start a red line promotion.") 13 | def test_when_price_is_reduced_by_5_percent(self): 14 | self.good.reduce_price(by=0.05) 15 | self.assertTrue(self.good.is_redline_promotion_effective_now(), "It should start a red line promotion.") 16 | def test_when_price_is_reduced_by_30_percent(self): 17 | self.good.reduce_price(by=0.30) 18 | self.assertTrue(self.good.is_redline_promotion_effective_now(), "It should start a red line promotion.") 19 | def test_when_price_is_reduced_by_5_percent_to_30_percent(self): 20 | self.good.reduce_price(by=0.10) 21 | self.assertTrue(self.good.is_redline_promotion_effective_now(), "It should start a red line promotion.") 22 | 23 | class given_a_good_with_multiple_price_changes_one_yesterday_one_today(unittest.TestCase): 24 | def setUp(self): 25 | self.yesterday = datetime.datetime.strptime('2015-03-28 12:14:12', '%Y-%m-%d %H:%M:%S') 26 | self.today = datetime.datetime.strptime('2015-03-29 12:14:12', '%Y-%m-%d %H:%M:%S') 27 | self.good = Good(price=100.00) 28 | self.good.reduce_price(by=0.05, effective=self.yesterday) 29 | self.good.reduce_price(by=0.1, effective=self.today) 30 | def test_when_price_is_calculated_for_yesterday(self): 31 | good_price = self.good.get_price(effective=self.yesterday) 32 | self.assertEqual(good_price, 95.00, "It should have only the inital price reduction.") 33 | def test_when_price_is_calculated_for_today(self): 34 | good_price = self.good.get_price(effective=self.today) 35 | self.assertEqual(good_price, 85.50, "It should compound the price reductions.") 36 | 37 | class given_a_good_with_a_price_change_in_the_last_thirty_days(unittest.TestCase): 38 | def setUp(self): 39 | self.todays_date = datetime.datetime.strptime('2015-03-29 12:14:12', '%Y-%m-%d %H:%M:%S') 40 | self.good = Good(price=200.00) 41 | self.good.reduce_price(by=0.05, effective=datetime.datetime.strptime('2015-03-01 17:59:59', '%Y-%m-%d %H:%M:%S')) 42 | def test_when_price_is_reduced_by_5_percent(self): 43 | red_line_promotion_started = self.good.reduce_price(by=0.05, effective=self.todays_date) 44 | self.assertFalse(red_line_promotion_started, "It should NOT start a red line promotion.") 45 | 46 | class given_a_good_with_a_price_change_before_the_last_thirty_days(unittest.TestCase): 47 | def setUp(self): 48 | self.todays_date = datetime.datetime.strptime('2015-03-29 12:14:12', '%Y-%m-%d %H:%M:%S') 49 | self.good = Good(price=200.00) 50 | self.good.reduce_price(by=0.05, effective=datetime.datetime.strptime('2015-02-26 11:59:59', '%Y-%m-%d %H:%M:%S')) 51 | def test_when_price_is_reduced_by_5_percent(self): 52 | red_line_promotion_started = self.good.reduce_price(by=0.05, effective=self.todays_date) 53 | self.assertTrue(red_line_promotion_started, "It should start a red line promotion.") 54 | 55 | class given_a_good_in_a_red_pencil_promotion(unittest.TestCase): 56 | def setUp(self): 57 | self.yesterday = datetime.datetime.strptime('2015-03-28 12:14:12', '%Y-%m-%d %H:%M:%S') 58 | self.today = datetime.datetime.strptime('2015-03-29 12:14:12', '%Y-%m-%d %H:%M:%S') 59 | self.good = Good(price=200.00) 60 | red_line_promotion_started = self.good.reduce_price(by=0.05, effective=self.yesterday) 61 | assert red_line_promotion_started, "A redline promotion should be started." 62 | def test_when_price_is_reduced_by_5_percent(self): 63 | red_line_promotion_started = self.good.reduce_price(by=0.05, effective=self.today) 64 | self.assertFalse(red_line_promotion_started, "It should NOT start another red line promotion.") 65 | 66 | class given_a_good_price(unittest.TestCase): 67 | def test_when_reduced_by_some_percentage(self): 68 | good_price = 100.00 69 | reduced_price = reduce_price_of(good_price, by=0.05) 70 | self.assertEqual(reduced_price, 95.00, "It should reduce the price by the percentage amount.") 71 | --------------------------------------------------------------------------------