· 5 years ago · May 03, 2020, 05:48 AM
1from abc import ABCMeta, abstractmethod
2#abstractmethod and ABC metaclass is imported into the program
3
4from random import randint
5#a randit module is imported here
6
7from time import gmtime, strftime
8
9import datetime
10#the datetime module is imported here
11
12import sqlite3
13#this is used to import sql database inyo the program
14
15import re
16#this is used to import into the program a module called regex
17
18conn = sqlite3.connect('IconMaclekVirtualRestaurant1.sql')
19cur = conn.cursor()
20#connection to the sql database is
21
22
23register_admintable = '''CREATE TABLE IF NOT EXISTS admin_details(
24 admin_ID INTEGER PRIMARY KEY,
25 first_name TEXT,
26 last_name TEXT,
27 admin_password TEXT)
28 '''
29cur.execute(register_admintable)
30#a table is created called admin_details is created here which contains the admin details such as names, adminID and password
31
32admin_login_history = '''CREATE TABLE IF NOT EXISTS admin_history(
33 admin_ID TEXT,
34 Date_and_time TEXT,
35 logged_out TEXT)
36 '''
37cur.execute(admin_login_history)
38#a table is created called admin_history is created here which contains the admin details such as adminID and date and time of log in
39
40foods_for_sale = '''CREATE TABLE IF NOT EXISTS foods_available(
41 foods TEXT PRIMARY KEY,
42 price INTEGER)
43 '''
44cur.execute(foods_for_sale)
45#a table named foods_available is created here, this table is used to store the foods available for sale and each price
46
47create_food = '''INSERT INTO foods_available(foods, price)
48 VALUES
49 ('Jollof Rice', 1000),
50 ('Ofada Rice', 1200),
51 ('Fried Rice', 1300),
52 ('Semovita', 500),
53 ('Amala', 500),
54 ('Pounded Yam', 500),
55 ('Egunsi Soup', 500),
56 ('Okro Soup', 500),
57 ('Vegetable Soup', 500),
58 ('Pizza', 5000),
59 ('Ice Cream', 1000),
60 ('Meat Pie', 500)'''
61try:
62 cur.execute(create_food)
63 conn.commit()
64 #the foods available and the price are inputed into the table foods_available here
65except sqlite3.IntegrityError:
66 pass
67
68register_customertable = '''CREATE TABLE IF NOT EXISTS user_details(
69 User_ID INTEGER PRIMARY KEY,
70 first_Name TEXT,
71 last_Name TEXT,
72 address TEXT,
73 password TEXT,
74 phone_Number TEXT)
75 '''
76cur.execute(register_customertable)
77#a user_details table is created here which does same function like the admin_details table, but this accepts user details instead of admin details
78
79
80cushistorytable = '''CREATE TABLE IF NOT EXISTS history(
81 user_ID TEXT,
82 food_Ordered TEXT,
83 price INTEGER,
84 date_ordered TEXT)
85 '''
86cur.execute(cushistorytable)
87# a history table is created here which include the user id, food ordered, price and date ordered
88
89
90class Customer(metaclass = ABCMeta):
91 @abstractmethod
92 def register():
93 return 0
94
95
96 @abstractmethod
97 def logIn():
98 return 0
99
100 @abstractmethod
101 def checkDetails():
102 return 0
103
104 @abstractmethod
105 def makeOrder():
106 return 0
107
108 @abstractmethod
109 def makePayment():
110 return 0
111
112 @abstractmethod
113 def checkHistory():
114 return 0
115
116
117#an abstract base class is created here which the class CustomerServices is made to inherit fromit, this is to ensure that none of the methods under customerService class are being missed out, they are made to return 0 cos they dont really have a definition of their own
118
119class CustomerServices(Customer):
120
121 def register(self, userID):
122 try:
123 self.userID = userID
124 print()
125 print("Account creation has been successful")
126 print(f"Your log in details are:\n1.user ID = {userID}. \n2.password = {password} ")
127 #this will print out the userID and the password
128
129 Query1 = cur.execute('''INSERT INTO user_details (User_ID, first_Name, last_Name, address, password, phone_Number) VALUES(?,?,?,?,?,?)''',(userID, firstName, lastName, address, password, phoneNumber))
130 conn.commit()
131 return True
132 #the method register is made to prompt a user to input his/her details such as password, phonenumber, address, names and the details are added to a table already created called user details
133
134 except sqlite3.IntegrityError:
135 print('Glitch in our system, try again')
136 return False
137
138 def logIn(self):
139 #a login mehod of class customerservice is made
140 query1 = cur.execute("SELECT user_ID, password from user_details")
141
142 #user_ID and password saved in the user details are selected
143 data = query1.fetchall()
144 details = {}
145 for dat in data:
146 details[dat[0]] = dat[1]
147 #this is used to fetch the userID and password in the table and a dictionary is made where the userID is the key and the password is the value
148
149 if userID in details.keys() and details[userID] == password:
150 print("Login Successful")
151 return True
152 #if the user ID provided by the user is in tbe dictionary and the password is the value then the login is successful and else the log in is not succesful and a message saying wrong details will be printed.
153
154 else:
155 print("Wrong details")
156 return False
157
158
159 def checkDetails(self, userID):
160 self.userID = userID
161 Query = '''SELECT * FROM user_details WHERE User_ID == {}'''.format(userID)
162 query = cur.execute(Query)
163 query = query.fetchall()
164 #the user details table is selected here and made to print
165 print("user ID: ", query[0][0])
166 print("First Name: ", query[0][1])
167 print("Last Name: ", query[0][2])
168 print("Address: ", query[0][3])
169 print("Phone Number: ", query[0][5])
170 #since the brings out a datatype like a list, and then the userID and so are printed using indexes. since the user is inserted first, it will be in index [0] and others follows same way
171
172
173 def makeOrder(self, totalitems, details):
174 totalamount = 0
175 #totalamount is the total price of the foods bought
176
177 for i in totalitems:
178 totalamount = totalamount + details[i]
179 #for every item in the totalitems list, add the former price of total amount to it. the prices of the foods are the value in the details dictionart
180 return totalamount
181 # the total amount should be returned
182
183
184#this method is used to check if an atm number is valid or not by using luhm's algorithm after that the total amount of items bought is deducted from the account
185 def makePayment(self, numbers, totalitems, totalamount,h):
186 print()
187 self.totalitems = totalitems
188 self.numbers = numbers
189
190 try:
191 atmcheck = [int((int(number)*2)/10) + (int(number)*2)%10 for number in numbers[::-1][1::2]] + [int(number) for number in numbers[::-1][::2]]
192 print("Valid card number!") if sum(atmcheck)%10 == 0 and h != 'check' else "Invalid card number!"
193
194 now = datetime.datetime.now()
195 if h =='check':
196 pass
197 else:
198 print(f"you ordered for {totalitems} at {now} and a fee of {totalamount} has been deducted from your bank account")
199 return True
200 except ValueError:
201 print("Invalid details") #a value error is handled here and prevented using exception handling.
202 return False
203
204 def checkHistory(self):
205 print()
206 query = '''SELECT * FROM history WHERE user_ID == {}'''.format(userID)
207 query = cur.execute(query).fetchall()
208 #all the data in the table history where the userID is thst of the particular user is fetched
209
210 for det in query:
211 print('\nyou bought \nFood-->{}\nPrice-->{}\nDate-->{}'.format(det[1],det[2],det[3]))
212 #this wll print out the food bought, time and date in that format for every order taken.
213 #this method will be used to to select the history details from the history table
214
215
216class Admin(metaclass = ABCMeta):
217 @abstractmethod
218 def registerAdmin():
219 return 0
220
221
222 @abstractmethod
223 def loginAdmin():
224 return 0
225
226 @abstractmethod
227 def addFood():
228 return 0
229
230 @abstractmethod
231 def removeFood():
232 return 0
233
234 @abstractmethod
235 def viewOrders():
236 return 0
237
238#an abstract base class is created here which the class AdminServices is made to inherit from it, this is to ensure that none of the methods under AdminService class are being missed out
239
240
241
242
243class AdminServices(Admin):
244
245 #this works same way like the register method in the customerService class
246 def registerAdmin(self, adminID):
247
248 try:
249 print()
250 self.adminID = adminID
251 print("Account creation is successful")
252 print(f"Your log in details are:\n1.adminID = {self.adminID}.\n2.password = {adminPassword} ")
253 Query4 = cur.execute("INSERT INTO admin_details VALUES (?,?,?,?)", (adminID, adminFirstName, adminLastName, adminPassword))
254 conn.commit()
255 return True
256
257
258 except sqlite3.IntegrityError:
259 print('Glitch in our sytem, its not you, its us, Try Again')
260 return False
261
262 #this works same way like the login method in the CustomerService class
263 def loginAdmin(self):
264
265 query1 = cur.execute("SELECT admin_ID, admin_Password from admin_details")
266 data = query1.fetchall()
267 details = {}
268
269 for dat in data:
270 details[dat[0]] = dat[1]
271
272 if adminID in details.keys() and details[adminID] == adminPassword:
273 print("Login Successful")
274 return True
275
276 else:
277
278 print("Wrong details")
279 return False
280
281
282
283 def addFood(self, food, price):
284
285 try:
286 Query2 = cur.execute('''INSERT INTO foods_available(foods, price) VALUES(?, ?)''',(food, price))
287 conn.commit()
288 print('{} has been added to the menu'.format(food))
289 #this method is used to insert new food and price into foods available table
290
291 except sqlite3.IntegrityError:
292 print('Food already in menu')
293 return False
294
295 def removeFood(self, food):
296
297 show_foods = "SELECT * FROM foods_available"
298 #the data in foods available are extracted here
299 foods = cur.execute(show_foods)
300 data = foods.fetchall()
301
302 details = {}#a dictionary is created
303
304 for dat in data:
305 details[dat[0]] = dat[1]
306
307 if food in details.keys():
308 Query3= "DELETE FROM foods_available WHERE foods ='"+ food +"'"
309 #the name of the food inputed will be deletedfrom the foods_available table
310 cur.execute(Query3)
311 conn.commit()
312 print('{} has been removed from the menu'.format(food))
313 #this method deletes food and prices from the foods_available table
314
315 else:
316 print('You can not remove food that is not on the menu')
317
318
319
320 def viewOrders(self, query4):
321
322 if len(query4) > 0:
323 for det in query4:
324 print('\nuserID "{}" bought \nFood-->{}\nPrice-->{}\nDate-->{}'.format(det[0],det[1],det[2],det[3]))
325 #this method prints out the history made by all the customers
326
327 else:
328 print('No orders yet')
329
330admin = AdminServices()
331#an object of AdminServices class is made here
332
333customer = CustomerServices()
334#an object of CustomerService class is made here
335
336print("WELCOME TO ICON MACLEK VIRTUAL RESTAURANT")
337print("YOUR SATISFACTION IS OUR UTMOST CONCERN")
338print('_'*60)
339
340while True:
341#this is used to create a loop
342
343 print("Enter 1 to continue as an admin\nEnter 2 to continue as a customer\nEnter 3 to exit")
344 print("Don't go on as an admin if you are not")
345
346 continuePhase = input()
347 #the user is prompt to enter a number here
348
349
350 if continuePhase == str(1):
351
352 while True:
353
354 print()
355 print("Enter 1 to register if you are a new user")
356 print("Enter 2 to log in if you have an existing account")
357 print("Enter 3 to go back to the previous menu")
358
359 adminChoice = input()
360 #if the input is 1, a while loop is also created, and the user is prompt to enter another input, this will take the user to register or log in or exit
361
362 if adminChoice == str(1):
363
364 adminID = randint(100000, 999999)
365 #a random integer number between the range of 100000 and 999999 is generated here
366
367 print("Enter your first name")
368 adminFirstName = input().title()
369 while not adminFirstName.isalpha():
370 adminFirstName = input('First Name: ').title()
371
372 print()
373
374 print("Enter your last name")
375 adminLastName = input().title()
376 while not adminLastName.isalpha():
377 adminLastName = input('Last Name: ').title()
378 #the title() works by capitalizing the first letters in each word
379
380 print()
381
382 print("Enter your password, password must be at least 6 characters long")
383 #the user is prompt to enter his names, then password
384
385 while True:
386
387 adminPassword = input()
388
389 if len(adminPassword) < 6 or " " in adminPassword:
390 print("Password weak. Make sure there is no space in your password")
391
392 else:
393
394 break
395 #if the length of the password is not up to 6 or there's a space in the password, an invalid password message will be generated and the user will be made to input another password, this will continue until the user enter the desired password'
396
397 admin.registerAdmin(adminID)
398 #the register method is then call on the admin object
399
400 elif adminChoice == str(2):
401
402 print("Enter your adminID")
403 adminID = input()
404 while not adminID.isnumeric():
405 adminID = input('Check your ID')
406
407 adminID = int(adminID)
408 #the input is then converted to integer here
409
410 print("Enter your password")
411 adminPassword = input()
412 #the user is promt to enter his password
413 print()
414 adminloginstatus = admin.loginAdmin()
415 #the login method is called on the admin class
416
417
418 if adminloginstatus == True:
419 #if the return value of the invoking of the login method is True, then a loop is created which continually accepts input from the user.
420 logged_in = strftime("%Y-%m-%d %H:%M:%S", gmtime())
421 query = cur.execute('''INSERT INTO admin_history(admin_ID, Date_and_time) VALUES(?, ?)''',(adminID, logged_in))
422 conn.commit()
423
424 while True:
425
426 print()
427 print("Enter 1 to add to list of foods Available")
428 print("Enter 2 to remove from list of foods Available")
429 print("Enter 3 to view order(s)")
430 print("Enter 4 to go to the previous menu")
431 print()
432
433 adminChoice = input()
434
435 if adminChoice == str(1):
436
437 print()
438
439 print("Enter the added food")
440 food = input().title()
441 while not food.isalpha():
442 food = input('Check the food name: ').title()
443
444 print("Enter the food's price")
445 price = input()
446 while not price.isnumeric():
447 price = input('Check the price: ')
448 admin.addFood(food, price)#the addfood method is invoked on the admin object
449 #if the input is 1, the user is prompt to enter the name of the food and its price after which the addFoof will add the food and price to the goods_available table
450
451
452 elif adminChoice == str(2):
453
454 print()
455
456 print("Enter the removed food")
457 food = input().title()
458 while not food.isalpha():
459 food = input('Check the food name: ').title()
460 admin.removeFood(food)#the removeFood method is invoked on the admin object, the food and its price will be removed from the foods_available table.
461#if the input is 2, the user is prompt to enter the food that should be deleted
462
463 elif adminChoice == str(3):
464
465 print()
466
467 print("Enter date(yyyy-mm--dd")
468 dateOrdered = input()
469
470 Query4 = '''SELECT * FROM history WHERE date_ordered ==''' + "'" + dateOrdered +"'"
471 query4 = cur.execute(Query4)
472
473 while not re.match(re.compile(r'^[0-9]{4}-[0-9]{2}-[0-9]{2}$'),dateOrdered):
474 print("invalid input")
475 dateOrdered = input('enter date (yyyy-mm-dd): ')
476 admin.viewOrders(query4.fetchall())
477
478
479 #the view order method is invoked on the admin class and the data selected will be printed out
480
481 elif adminChoice == str(4):
482 logged_out = strftime("%Y-%m-%d %H:%M:%S", gmtime())
483 query = cur.execute('''INSERT INTO admin_history(admin_ID, logged_out) VALUES(?, ?)''',(adminID, logged_out))
484 conn.commit()
485 break #this will break from the while loop created above
486
487 else:
488 print("Invalid Input")
489 #if anything else is entered by the user, a invalid input message will be printed
490
491 elif adminChoice == str(3):
492
493 break #if the adminchoice is 3, then then the while loop created for the input which make the program go back to the previous entry
494
495 else:
496 print("Invalid Input")
497 ##if anything else is entered by the user, a invalid input message will be printed
498
499 elif continuePhase == str(2):
500
501 while True:
502
503 print("Enter 1 to register if you are a new user")
504 print("Enter 2 to log in if you have an existing account")
505 print("Enter 3 to go back to the previous menu")
506 userChoice = input()
507 print()
508
509 if userChoice == str(1):
510
511 userID = randint(100000, 999999)
512 #a random integer number between the range of 100000 and 999999 is generated here
513
514 print("Enter your first name")
515 firstName = input().title()
516 while not firstName.isalpha():
517 firstName = input('First Name: ').title()
518
519 print()
520
521 print("Enter your last name")
522 lastName = input().title()
523 while not lastName.isalpha():
524 lastName = input('Last Name: ').title()
525 #the user is prompt to enter his names
526
527 print()
528
529 print("Enter your password, password must be at least 6 characters long")
530
531 while True:
532
533 password = input()#the user is prompt to enter his password
534
535 if len(password) < 6 or " " in password: #if the length of the password is not up to 6 or there is a space in the password inputed,, print password weak and the user is made to enter another because of the while loop
536 print("Password weak")
537
538 else:
539 break#else if the password is greater than 6, then break from the loop
540
541 print()
542
543 print("Enter your address, as this will help us locate you\nMake sure a well described address is given to avoid late or no delivery of your order")
544 address = input()
545
546 print()
547
548 print("Enter your phoneNumber.\nMake sure the number can be accessed")
549
550 while True:
551
552 phoneNumber = input()
553 while not phoneNumber.isnumeric():
554 phoneNumber = input('Check the phone number entered')
555
556 #a phone number should be strictly numbers
557
558 if len(phoneNumber) != 11 or " " in phoneNumber:
559 print("Invalid Number, check if the Number is a valid number")
560
561 else:
562
563 if phoneNumber.startswith("090") or phoneNumber.startswith("070") or phoneNumber.startswith("080") or phoneNumber.startswith("081"):
564
565 break
566
567 else:
568
569 print("Invalid Number, Check if the Number is Correct")
570#before inputing the user's phone number a while loop is created so that the user can re enter the number if the number entered by the user is not validated. the loop breaks if the phone number starts with the correct digits and if its 11 in number and it contains no space
571
572 customer.register(userID)#the register method is called on the customer class here.
573
574 print()
575
576 elif userChoice == str(2):
577
578 #user_ID and password saved in the user details are selected
579 #the user is prompt to enter the userID he/she is registered with
580
581 print("Enter your userID")
582 userID = input()
583 while not userID.isnumeric():
584 userID = input('Check your ID')
585 userID = int(userID)
586
587
588 print("Enter your password")
589 password = input()
590 #the user is prompt to enter the password he registered with.
591
592 loginStatus = customer.logIn()
593 #the log in is invoked here and assigned to a variable called loginStatus
594
595 print()
596
597 if loginStatus is True:
598
599 #if loginStatus returns true, a while loop is created, then input is taken from the user and the input is assigned to a variable called userChoice
600
601 while True:
602
603 print()
604 print("Enter 1 to Order")
605 print("Enter 2 to check history")
606 print("Enter 3 to check customer details")
607 print("Enter 4 to go to the previous menu")
608 print()
609
610 userChoice = input()
611
612 print()
613
614 #while log in, a loopbis created where you can order, check history and chevk customer details, the user is prompt to enter a number, and the input is assigned to a variable called userChoice
615
616 if userChoice == str(1):
617
618 totalitems = []
619
620 show_foods = "SELECT * FROM foods_available"
621 #the data in foods available are extracted here
622 foods = cur.execute(show_foods)
623 data = foods.fetchall()
624
625 details = {}#a dictionary is created
626 for dat in data:
627 details[dat[0]] = dat[1]
628 #the foods are made the keys and the prices of the foods are made the values in the dictionary assigned to a variable called details.
629
630 while True:
631
632 print("Enter your food, Enter quit to stop ordering")
633 foodordered = input().title()
634
635 if foodordered == "Quit":
636
637 break
638
639 else:
640
641 p = '''SELECT foods,price FROM foods_available where foods =='''+ "'"+foodordered+"'"
642 p = cur.execute(p).fetchall()
643
644 if len(p) > 0:
645 print(f'{foodordered} added to cart')
646 totalitems.append(foodordered)
647
648 else:
649
650 print(f"{foodordered} not available")
651
652 totalamount = customer.makeOrder(totalitems, details)
653 #the totalamount is returned when makeorder method is invoked on the customer class
654
655 if totalamount > 0:
656
657 print("Enter your correct atm details")
658
659 while True:
660
661 numbers = input()
662 while not numbers.isnumeric():
663 numbers = input('Check your atm details')
664 if numbers == str(1):
665 False
666 elif len(numbers) != 16 and customer.makePayment(numbers, totalitems,totalamount,'check'):
667
668 print("Wrong card numbers Enter atm details again,Press 1 to exit (your cart will be emptied)")
669
670 else:
671
672 customer.makePayment(numbers, totalitems,totalamount,'here')
673
674
675 #the user is prompt to enter his atm card numbers, if the number is not up to 16, the loop makes the user re-enter it. then the makepayment method is invoked on the customer object if only the total amount of item bought is greater than zero i.e if any item is bought, if not the program breaks to the previous one.
676 dateordered = str(datetime.date.today()) #dateordered is generated here using the datetime module
677 totalitems = ' and '.join(totalitems)
678 #totalitems is made a string here by joining the items together by and if they're more than one
679 query1 = cur.execute('''INSERT INTO history(user_ID, food_Ordered,price, date_ordered) VALUES(?,?,?,?)''',(userID,totalitems,totalamount,dateordered))
680 conn.commit()
681 #the userID, food, price of food ordered and the date is inserted into the history table
682
683 break
684 #the loop breaks here
685
686
687 elif userChoice == str(2):
688
689 print("checking history")
690 customer.checkHistory()
691 #the checkhistory method is invoked on the customer object if the user choice is 2
692
693 elif userChoice == str(3):
694
695 print()
696 customer.checkDetails(userID)
697 #the checkDetails method is invoked on the customer object if the user choice is 3
698
699
700
701 elif userChoice == str(4):
702 break#the loop breaks if the userchoice is 4 and it returns to the previous entry
703
704 else:
705 print("Invalid Input")
706 #if anything else is inputed apart from 1,2,3 or 4 then an invalid input message is printed
707
708
709
710 elif userChoice == str(3):
711 break #if the user input is 3, the loop breaks
712
713 else:
714 print("invalid input")
715 #if anything else is inputed apart from 1,2,or 3 then an invalid input message is printed
716
717
718 elif continuePhase == str(3):
719 break
720 #if the continuephase is 3, then the program exits from the loop and the program ends
721
722 else:
723 print("Invalid Input")
724 #if anything else is inputed apart from 1,2,or 3 then an invalid input message is printed
725
726conn.close()
727#the connection to sql is closed here