forked from chrismedrela/2018-06-06-prework
-
Notifications
You must be signed in to change notification settings - Fork 0
/
exercise-2.py
150 lines (125 loc) · 5.7 KB
/
exercise-2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# encoding: utf-8
"""
Open Close Principle to jedna z pięciu zasad SOLID. Mówi ona, że klasy i funkcje
powinny być otwarte na rozszerzenie i zamknięte na modyfikacje. Innymi słowy,
powinno być możliwe ponowne wykorzystanie kodu bez modyfikowania go.
Poniżej znajduje się funkcja `calculate_discount_percentage`, która jest pewną
strategią wyliczania przysługującej klientowi zniżki wyrażonej w procentach.
Każdy klient jest instancją klasy Customer i ma trzy pola:
- first_purchase_date -- data pierwszego zakupu lub None, jeżeli jest to nowy
klient
- birth_date -- data urodzenia
- is_veteran -- flaga informująca, czy dany klient jest VIPem
Zaimplementowano następującą strategię:
- seniorzy (65+) dostają 5% zniżki
- lojalni klienci, którzy są z nami od 1, 5 lub 10 lat, dostają odpowiednio 10%,
12% i 20% zniżki,
- nowi klienci dostają 15% zniżki
- veterani dostają 10% zniżki
- pozostali dostają 0% zniżki
- jeżeli przysługuje więcej niż jedna zniżka, zniżki nie sumują się i wybieramy
tę największą
Dodatkowo, niżej widzimy testy jednostkowe tej funkcji.
W tej funkcji złamano zasadę otwarte-zamknięte, ponieważ nie ma możliwości
ponownego wykorzystania jej.
Jako ćwiczenie, postaraj się zrefaktoryzować kod tak, aby możliwe było ponowne
użycie fragmentów obecnej strategii. Innymi słowy, powinno być możliwe
zaimplementowanie podobnej strategii (w której, przykładowo, nie ma zniżki dla
nowych klientów), bez duplikowania kodu.
"""
import datetime
import unittest
class Customer:
def __init__(self, first_purchase_date, birth_date, is_veteran):
assert isinstance(first_purchase_date, (type(None), datetime.datetime))
assert isinstance(birth_date, datetime.datetime)
assert isinstance(is_veteran, bool)
self.first_purchase_date = first_purchase_date
self.birth_date = birth_date
self.is_veteran = is_veteran
def calculate_discount_percentage(customer):
discount = 0
now = datetime.datetime.now()
year = datetime.timedelta(days=365)
if customer.birth_date <= now - 65*year:
# senior discount
discount = 5
if customer.first_purchase_date is not None:
if customer.first_purchase_date <= now - year:
# after one year, loyal customers get 10%
discount = 10
if customer.first_purchase_date <= now - 5*year:
# after five years, 12%
discount = 12
if customer.first_purchase_date <= now - 10*year:
# after ten years, 20%
discount = 20
else:
# first time purchase ==> 15% discount
discount = 15
if customer.is_veteran:
discount = max(discount, 10)
return discount
class CalculateDiscountPercentageTests(unittest.TestCase):
def setUp(self):
self.now = datetime.datetime.now()
self.year = datetime.timedelta(days=365)
def test_should_return_zero_for_casual_customer(self):
customer = Customer(first_purchase_date=self.now,
birth_date=self.now-20*self.year,
is_veteran=False)
got = calculate_discount_percentage(customer)
expected = 0
self.assertEqual(got, expected)
def test_should_return_15_for_new_client(self):
customer = Customer(first_purchase_date=None,
birth_date=self.now-20*self.year,
is_veteran=False)
got = calculate_discount_percentage(customer)
expected = 15
self.assertEqual(got, expected)
def test_should_return_10_for_veteran(self):
customer = Customer(first_purchase_date=self.now,
birth_date=self.now-20*self.year,
is_veteran=True)
got = calculate_discount_percentage(customer)
expected = 10
self.assertEqual(got, expected)
def test_should_return_5_for_a_senior(self):
customer = Customer(first_purchase_date=self.now,
birth_date=self.now-65*self.year,
is_veteran=False)
got = calculate_discount_percentage(customer)
expected = 5
self.assertEqual(got, expected)
def test_should_return_10_for_a_loyal_customer(self):
customer = Customer(first_purchase_date=self.now-1*self.year,
birth_date=self.now-20*self.year,
is_veteran=False)
got = calculate_discount_percentage(customer)
expected = 10
self.assertEqual(got, expected)
def test_should_return_12_for_a_more_loyal_customer(self):
customer = Customer(first_purchase_date=self.now-5*self.year,
birth_date=self.now-20*self.year,
is_veteran=False)
got = calculate_discount_percentage(customer)
expected = 12
self.assertEqual(got, expected)
def test_should_return_20_for_a_most_loyal_customer(self):
customer = Customer(first_purchase_date=self.now-10*self.year,
birth_date=self.now-20*self.year,
is_veteran=False)
got = calculate_discount_percentage(customer)
expected = 20
self.assertEqual(got, expected)
def test_should_return_maximum_discount(self):
customer = Customer(first_purchase_date=None,
birth_date=self.now-20*self.year,
is_veteran=True)
# eligible for 15% discount as a new client and 10% as a veteran
got = calculate_discount_percentage(customer)
expected = 15
self.assertEqual(got, expected)
if __name__ == "__main__":
unittest.main()