commit d843c41382f98408bb404621cbb18ca776f7ec8c Author: Andrew Date: Fri Nov 25 07:42:33 2022 +0200 Initial commit diff --git a/Project.py b/Project.py new file mode 100644 index 0000000..65e5a9d --- /dev/null +++ b/Project.py @@ -0,0 +1,499 @@ +# Install necessary libraries if they are not already installed +# Asenna tarvittavat kirjastot, jos niitä ei ole jo asennettu +try: + import matplotlib.pyplot as plt +except ImportError: + import os + os.system('pip install matplotlib') + import matplotlib.pyplot as plt +try: + from prettytable import PrettyTable +except ImportError: + import os + os.system('pip install prettytable') + from prettytable import PrettyTable +from datetime import datetime +import random +import string +now = datetime.now() + + +# Go back to main menu +# Palaa päävalikkoon + + +def back(): + input('\nPress ENTER to return to main menu...') + menu() + +# Modify vehicle.txt file +# Muokkaa vehicle.txt-tiedostoa + + +def modify(tf, mod): + if tf: + with open(r'Vehicle.txt', 'w+') as rew: + for w in mod: + rew.write(w) + +# Display cars available for rent +# Näytä autot vuokrattavissa + + +def displayCars(u): + table = PrettyTable(['Registration number', 'Model name', + 'Type (Ordinary/Premium)', 'Free mileage (km)', 'Daily rent (€)']) + with open(r'Vehicle.txt', 'r') as f1: + cars1 = f1.readlines() + for i in cars1: + i = i.split(',') + i = [x.replace('\n', "") for x in i] + if u == 'A': + if i[5] == 'A': + table.add_row([i[0], i[1], i[2], i[3], i[4]]) + elif u == 'R': + if i[5] == 'R': + table.add_row([i[0], i[1], i[2], i[3], i[4]]) + else: + print('\nInvalid choice.') + return + print(table) + +# Add and delete vehicles +# Lisää ja poista ajoneuvoja + + +def Add_Vehicle(): + lcpl = input('\nEnter Vehicle ID: ') + ehto = True + with open(r'Vehicle.txt', 'r') as fv: + vec = fv.readlines() + for vc in vec: + vc = vc.split(',') + if lcpl == vc[0]: + print('\nVehicle already exists in database.') + ehto = False + if ehto: + name = input('Enter Vehicle Name: ') + while True: + typ = input('Enter vehicle type (O/P): ') + if typ == 'P': + try: + mileage = float( + input("Enter Type-P Vehicle's mileage allowance: ")) + except Exception: + print('\nInvalid choice.\n') + continue + else: + mileage = str(mileage) + break + elif typ == 'O': + mileage = '0' + break + else: + print('\nInvalid choice.\n') + continue + while True: + try: + dailyrent = float(input("Enter daily rent rate: ")) + except Exception: + print('\nInvalid choice.\n') + continue + else: + dailyrent = str(dailyrent) + break + stat = input( + "Enter status (A/R, if choose R please add rent details to rentVehicle.txt): ") + with open(r'Vehicle.txt', 'a') as fa: + fa.write('\n'+lcpl + ','+name+','+typ + ',' + + mileage + ','+dailyrent+','+stat) + while True: + try: + con = input('\nDo you want to add another vehicle? (Y/N): ') + except Exception: + print("\nInvalid choice.") + continue + else: + if con == 'Y': + Add_Vehicle() + elif con == 'N': + menu() + return + else: + print("\nInvalid choice.") + continue + + +def Delete_Vehicle(): + lcpl2 = input('\nEnter Vehicle ID: ') + with open(r'Vehicle.txt', 'r') as fd: + ved = fd.readlines() + for vd in ved: + vd = vd.split(',') + if lcpl2 == vd[0]: + vd = ','.join(vd) + with open(r'deletedVehicles.txt', 'a') as fr: + fr.write(vd+'\n') + pos = ved.index(vd) + del ved[pos] + modify(True, ved) + break + else: + print("\nVehicle does not exist.") + while True: + try: + con = input('\nDo you want to delete another vehicle? (Y/N): ') + except Exception: + print("\nInvalid choice.") + continue + else: + if con == 'Y': + Delete_Vehicle() + elif con == 'N': + menu() + return + else: + print("\nInvalid choice.") + continue + +# Add rent details to files +# Lisää tiedostoihin vuokratiedot + + +def rentDetails(path, app): + plate = app.split(',') + if path == 1: + with open(r'rentVehicle.txt', 'a') as q: + q.write(str(app)) + print('\nCar '+plate[1]+' is rented successfully.') + elif path == 2: + with open(r'Transactions.txt', 'a') as p: + p.write(str(app)) + print('\nCar '+plate[1]+' is returned successfully.') + +# Generate Receipt ID and check if it is already taken +# Luo kuittitunnus ja tarkista, onko se jo varattu + + +def receiptID(): + while True: + code = ''.join([random.choice(string.ascii_letters + string.digits) + for n in range(10)]) + with open('rentVehicle.txt', 'r') as cd: + cdc = cd.readlines() + for cdi in cdc: + cdi = cdi.split(',') + if cdi[0] == code: + continue + else: + return code + +# Check Odometer reading +# Tarkista matkamittarin lukema + + +def odometer(way, qq): + if way == 1: + while True: + try: + vv = float( + input('Enter odometer reading at time of renting: ')) + except Exception: + print('\nOdometer reading must be a float or an integer.\n') + continue + else: + return vv + elif way == 2: + while True: + try: + ww = float( + input('Enter odometer reading at time of returning: ')) + except Exception: + print('\nOdometer reading must be a float or an integer.\n') + continue + else: + if (ww) < (qq): + print( + '\nEnd odometer value must be larger than initial odometer value.\n') + continue + else: + return ww + +# Add accessories +# Lisää lisävarusteita + + +def accessories(): + while True: + paina = input('\nDo you want to add them? (Y/N): ') + if paina == 'Y': + return 20 + elif paina == 'N': + return 0 + else: + print("\nInvalid choice.") + continue + +# Rent a car +# Vuokrata auton + + +def rentVehicle(id1): + with open(r'Vehicle.txt', 'r') as f2: + cars2 = f2.readlines() + for j in cars2: + j = [i.rstrip() for i in j.split(',')] + if id1 == j[0]: + if j[5] == 'A': + rentID = input('Enter Renter ID: ') + odo = str(odometer(1, 0)) + acc = 0 + recid = receiptID() + if j[2] == 'P': + print( + '\nThe following accessories could be added to your vehicle for only €20:') + print('1. HD Dash Cam') + print('2. GPS Navigation') + print('3. Engine Heater') + acc = accessories() + print('\nCar '+j[0]+' is rented to '+rentID) + table1 = PrettyTable(['Receipt ID', recid]) + table1.add_row(['Renter ID', rentID]) + table1.add_row(['Vehicle ID', id1]) + table1.add_row(['Description', j[1]]) + table1.add_row(['Status', 'A -> R']) + table1.add_row(['Accessories', '€'+str(acc)]) + table1.add_row(['Daily rate', '€'+j[4]]) + table1.add_row(['Date/time of rent', + now.strftime("%d/%m/%Y %H:%M")]) + table1.add_row(['Rent starting odometer', odo]) + print(table1) + appnew = (recid+','+id1+','+rentID+',' + + now.strftime("%d/%m/%Y %H:%M") + + ','+odo+','+str(acc)+'\n') + rentDetails(1, appnew) + j[5] = 'A\n' + dx = cars2.index(','.join(j)) + j[5] = 'R\n' + j = ','.join(j) + cars2[dx] = j + return True, cars2 + elif j[5] == 'R\n': + print('\nVehicle is on rent.') + return False, [] + else: + print('\nVehicle does not exist.') + return False, [] + +# Return a car +# Palauta auton + + +def rentComplete(id2): + with open(r'rentVehicle.txt', 'r') as f3: + cars3 = f3.readlines() + for r in cars3: + r = r.split(',') + if id2 == r[0]: + with open(r'Vehicle.txt', 'r') as f4: + rented = f4.readlines() + for v in rented: + v = v.split(',') + if v[5] == 'R\n': + odo2 = str(odometer(2, float(r[4]))) + startdate = r[3] + dayrent = datetime.strptime( + startdate, '%d/%m/%Y %H:%M') + daydelta = (now - dayrent).days + kms = float(odo2)-float(r[4]) + typefee = 0 + if v[2] == 'O': + typefee = 0.020 + elif v[2] == 'P': + typefee = 0.025 + charge = str( + ((daydelta+1)*float(v[4]))+((daydelta+1)*float(r[5]))+(kms*typefee)) + print('\nCar '+r[1]+' is returned from '+r[2]) + table2 = PrettyTable(['Receipt ID', r[0]]) + table2.add_row(['Renter ID', r[2]]) + table2.add_row(['Vehicle ID', r[1]]) + table2.add_row(['Description', v[1]]) + table2.add_row(['Status', 'R -> A']) + table2.add_row( + ['Accessories', '€'+r[5].strip('\n')]) + table2.add_row(['Daily rate', '€'+v[4]]) + table2.add_row(['Date/time of rent', r[3]]) + table2.add_row(['Date/time of return', + now.strftime("%d/%m/%Y %H:%M")]) + table2.add_row(['Number of days', daydelta+1]) + table2.add_row(['Rent starting odometer', r[4]]) + table2.add_row(['Rent end odometer', odo2]) + table2.add_row(['Distance traveled', kms]) + table2.add_row(['Rental charges', '€'+charge]) + print(table2) + appdone = (id2+','+r[1]+',' + r[2]+',' + now.strftime( + "%d/%m/%Y %H:%M") + ','+r[4]+','+odo2+','+charge+'\n') + rentDetails(2, appdone) + dy = rented.index(','.join(v)) + v[5] = 'A\n' + v = ','.join(v) + rented[dy] = v + return True, rented + else: + print( + "Receipt ID found but vehicle is not on rent.") + return False, [] + else: + print('\nReceipt ID does not exist.') + return False, [] + +# Data visualization +# Tietojen visualisointi + + +def Graph1(): + ordinary = 0 + premium = 0 + with open(r'Vehicle.txt', 'r') as g: + gc = g.readlines() + for gline in gc: + gline = gline.split(',') + gline = [gl.replace('\n', '') for gl in gline] + if gline[2] == 'O': + ordinary += 1 + elif gline[2] == 'P': + premium += 1 + labels = ['Ordinary', 'Premium'] + data = [ordinary, premium] + plt.xticks(range(len(data)), labels) + plt.xlabel('Types') + plt.ylabel('Amounts') + plt.title('Number of Ordinary and Premium Vehicles') + plt.bar(range(len(data)), data, color='pink') + plt.show() + + +def Graph2(): + dct = {} + sanakirja = {} + total = 0 + with open(r'Transactions.txt', 'r') as g2: + gd = g2.readlines() + for item in gd: + if len(dct.keys()) == 12: + break + item = item.split(',') + item = [gh.replace('\n', '') for gh in item] + item[6] = float(item[6]) + total += item[6] + paivamaara = datetime.strptime( + item[3], '%d/%m/%Y %H:%M') + paiva = paivamaara.strftime('%m/%Y') + try: + dct[paiva] = item[6]+float(dct[paiva]) + except KeyError: + dct[paiva] = 0 + dct[paiva] = item[6]+float(dct[paiva]) + d_items = dct.items() + sortdct = sorted(d_items) + for sana in sortdct: + sanakirja[sana[0]] = sana[1] + kuukausi = sanakirja.keys() + tulo = sanakirja.values() + plt.plot(kuukausi, tulo, color='maroon', marker='*') + plt.title('Income earned for last '+str(len(dct.keys()))+' month(s)') + plt.xlabel('Month') + plt.ylabel('Income (€/month)') + plt.grid(True) + plt.show() + + +# Remove extra lines +# Poista ylimääräiset rivit + +def extraLinesTerminator(): + with open('Vehicle.txt', 'r') as z: + content = z.readlines() + for i in content: + if i == '\n' or not i: + content.remove(i) + modify(True, content) + +# Main menu +# Päävalikko + + +def menu(): + extraLinesTerminator() + print('\n Vehicle Menu') + print('Display Cars 1') + print('Add/delete Vehicle 2') + print('Rent Vehicle 3') + print('Complete Rent 4') + print('Reporting Vehicle Information 5') + print('Exit 6') + try: + choice = int(input('\nChoose your options: ')) + except Exception: + print("\nInvalid choice.") + back() + else: + if choice == 1: + slt = input( + '\nA for available vehicles or R for vehicles on rent: ') + displayCars(slt) + back() + elif choice == 2: + try: + slt2 = int( + input('\n1 to add vehicles and 2 to delete vehicles: ')) + except Exception: + print("\nInvalid choice.") + back() + else: + if slt2 == 1: + Add_Vehicle() + elif slt2 == 2: + Delete_Vehicle() + else: + print("\nInvalid choice.") + back() + elif choice == 3: + idc2 = input('\nEnter Vehicle ID: ') + o2 = rentVehicle(idc2) + modify(o2[0], o2[1]) + back() + elif choice == 4: + idc3 = input('\nEnter Receipt ID: ') + o3 = rentComplete(idc3) + modify(o3[0], o3[1]) + back() + elif choice == 5: + print( + '\nDisplay the number of vehicles of each type: Ordinary and Premium 1') + print( + 'Display the income earned for last months (maximum 12) 2') + try: + opp = int(input('\nCHoose your options: ')) + except Exception: + print("\nInvalid choice.") + back() + else: + if opp == 1: + Graph1() + back() + elif opp == 2: + Graph2() + back() + else: + print("\nInvalid choice.") + back() + elif choice == 6: + print('\nThanks for using Car Rental System. Bye!') + return + else: + print('\nInvalid choice.') + back() + + +menu() diff --git a/Transactions.txt b/Transactions.txt new file mode 100644 index 0000000..cbc4ec1 --- /dev/null +++ b/Transactions.txt @@ -0,0 +1,7 @@ +c6AlovwPDn,ADH-402,140498-1242,02/12/2021 13:02,34525.0,34600.0,251.5 +u0AmvNZv0f,ADH-402,060598-2144,02/11/2021 13:02,33098.0,33190.0,651.84 +gzDd6pEPOa,TUI-263,5436547545,02/10/2021 13:02,46875.0,46900.0,80.625 +YlTNzhdrBT,FUW-161,6535436346,02/09/2021 13:19,21343.0,21398.0,101.375 +HWL13h5sMW,MKJ-634,3548769857,02/09/2021 13:28,232.0,987.0,1798.875 +f6BIrSvwPX,GTY-734,9876867,02/08/2021 13:36,35255.0,40923.0,273.36 +sXwiQ8gIXU,JHU-823,Musan,25/11/2022 07:26,1000.0,1089.0,121.78 diff --git a/Vehicle.txt b/Vehicle.txt new file mode 100644 index 0000000..5fb8eb4 --- /dev/null +++ b/Vehicle.txt @@ -0,0 +1,22 @@ +XJY-604,Hyundai Getz,O,0,45.0,A +AJB-123,BMW mini,P,200,65.0,A +WYN-482,Ford Fiesta,O,0,40.0,A +BKV-943,Ford Ikon,P,150,60.0,A +JMB-535,Ford Flex,O,0,50.0,A +MKJ-634,Ford Mustang Mach-E,P,180,80.0,A +GTY-734,Dacia Sandero,O,0,20.0,A +BTR-921,Dacia Duster,O,0,25.0,A +ADH-402,VW Golf,O,0,50.0,A +KJL-356,VW Tiguan,P,200,80.0,A +TUI-263,Skoda Octavia,P,150,60.0,A +FUW-161,Mercedes-Benz C-Class,P,200,80.0,A +MDF-347,Renault Clio,O,0,30.0,A +XIR-209,Renault Captur,O,0,40.0,A +QPC-417,Citroen C3,O,0,30.0,A +PEI-807,Citroen C5,O,0,40.0,A +KJE-215,Hyundai Elantra,O,0,30.0,A +LME-136,Hyundai Sonata,O,0,40.0,A +NDW-325,DS 3 Crossback,O,0,45.0,A +EID-210,Smart Forfour,O,0,35.0,A +JHU-823,Skoda Octavia,O,0,60.0,A +HYU-238,Skoda Enyaq iV,P,50.0,100.0,A \ No newline at end of file diff --git a/deletedVehicles.txt b/deletedVehicles.txt new file mode 100644 index 0000000..00e7a94 --- /dev/null +++ b/deletedVehicles.txt @@ -0,0 +1 @@ +EIH-313,Smart Forfour,O,0,35.0,A diff --git a/rentVehicle.txt b/rentVehicle.txt new file mode 100644 index 0000000..e2f9993 --- /dev/null +++ b/rentVehicle.txt @@ -0,0 +1,7 @@ +c6AlovwPDn,ADH-402,140498-1242,28/11/2021 12:52,34525.0,0 +u0AmvNZv0f,ADH-402,060598-2144,20/10/2021 13:02,33098.0,0 +gzDd6pEPOa,TUI-263,5436547545,30/09/2021 13:02,46875.0,20 +YlTNzhdrBT,FUW-161,6535436346,01/09/2021 13:19,21343.0,20 +HWL13h5sMW,MKJ-634,3548769857,15/08/2021 13:28,232.0,20 +f6BIrSvwPX,GTY-734,9876867,25/07/2021 13:28,35255.0,0 +sXwiQ8gIXU,JHU-823,Musan,24/11/2022 07:26,1000.0,0