POS Final Project

 avatar
unknown
python
3 years ago
33 kB
4
Indexable
from tkinter import*
from tkinter import messagebox, font
from abc import ABC, abstractmethod
from tkinter import filedialog

import matplotlib.pyplot as plt
import datetime
import os
import json
import pickle

class Prompt:
    
    def __init__(self):
        self.root = Tk()
        self.root.title("Menu")
        self.root.geometry("500x150")

        Label(self.root, text="Enter the name of your company to start your day, or click Analysis to enter statistic mode").pack(padx=10, pady=10)
        self.prompt = Entry(self.root, bd=5, width=35)
        self.prompt.pack()
        Button(self.root, text="Submit", command=self.setName, pady=5, padx=5).pack(pady=2, padx=2, side=RIGHT)
        Button(self.root, text="Analysis", command=self.enterAnalyse, pady=5, padx=5).pack(pady=2, padx=2, side=RIGHT)
        Button(self.root, text="Exit", command=self.root.quit, pady=5, padx=5).pack(pady=2, padx=2, side=RIGHT)
        
        self.root.mainloop()

    def enterAnalyse(self):
        self.root.destroy()
        Analysis()
    
    def setName(self):
        self.name = (self.prompt.get())
        try:
            self.root.destroy()
        except:
            self.anaWin.destroy()
        Main(self.name)

class Main:
    
    def __init__(self, name):
        self.mainWin = Tk()
        self.bg = '#f5f5f5'
        self.fg = '#424242'
        self.sec = '#eeeeee'
        self.mainWin.configure(bg=self.bg)
        self.defaultFont = font.nametofont("TkDefaultFont")
        self.defaultFont.configure(family="Calibri")
        
        self.name = name
        
        self.currentDate = str(datetime.datetime.now().year)+str(datetime.datetime.now().month).zfill(2)+str(datetime.datetime.now().day).zfill(2)
        
        self.taxRate = 1.0
        self.serRate = 1.0
        self.memberList = []
        self.memberOrder = 1
        self.productList = {}
        self.orderList = []
        self.memberVal = {"sil" : 1.0, "gold" : 1.0, "plat" : 1.0}
        self.mainWin.title(f"{self.name} Management System")
        self.mainWin.geometry("1280x720")
        self.loadSettings()
        self.loadMembership()
                    
        self.mainMenu()

        self.welPad = Label(self.mainWin, text="\t\t\t\t\t\t\t", bg=self.bg, fg=self.fg,)
        self.welPad.grid(row=0, column=0, padx=2, pady=2)
        Label(self.mainWin, text=datetime.date.today().strftime("%d/%m/%Y"), bg=self.bg, fg=self.fg, font=("Calibri", 10, font.BOLD)).grid(row=0, column=1, padx=2, pady=2, sticky=E)
        self.welFrame = LabelFrame(self.mainWin, text=f"Welcome to {self.name}", bg=self.bg, fg=self.fg, font=("Calibri", 10, font.BOLD))
        self.welFrame.grid(row=1, column=1, padx=2, pady=2, sticky=N)
        
        Label(self.welFrame, text="\n\tClick ""Order"" to start your day\t\t", bg=self.bg, fg=self.fg, font=("Calibri", 15, font.BOLD)).pack(pady=5)
        Label(self.welFrame, text="\tChoose the option in the menu bar for adjustment.\t\t", bg=self.bg, fg=self.fg, font=("Calibri", 15, font.BOLD)).pack(pady=5)
        Button(self.welFrame, text="Order", command=self.orderWin, padx=10, bg=self.bg, fg=self.fg, font=("Calibri", 10, font.BOLD)).pack(pady=25, padx=2, side=RIGHT)
        self.mainWin.mainloop()

    def loadSettings(self):
        if os.path.exists(f"{os.path.dirname(os.path.abspath(__file__))}\setting.json"):
            with open(f"{os.path.dirname(os.path.abspath(__file__))}\setting.json", 'r') as f:
                settingsLoad = json.loads(f.read())
                self.taxRate = settingsLoad["taxRate"]
                self.serRate = settingsLoad["serRate"]
                self.memberVal = settingsLoad["memberVal"]
                self.productList = settingsLoad["productList"]
        else:
            self.updateSettings()
    
    def loadMembership(self):
        if os.path.exists(f"{os.path.dirname(os.path.abspath(__file__))}\member.pickle"):
            with open(f"{os.path.dirname(os.path.abspath(__file__))}\member.pickle", 'rb') as f:
                self.memberList = pickle.load(f)
                    
                if len(self.memberList) > 0:
                    if self.memberList[-1].id[:8] == self.currentDate:
                        self.memberOrder = int(self.memberList[-1].id[9:]) + 1
        else:
            self.updateSettings()
            
    def updateSettings(self):
        with open(f"{os.path.dirname(os.path.abspath(__file__))}\member.pickle", 'wb') as f:
            pickle.dump(self.memberList, f)
        
        with open(f"{os.path.dirname(os.path.abspath(__file__))}\setting.json", 'w') as f:
            settingInit = {
                "taxRate" : self.taxRate,
                "serRate" : self.serRate,
                "memberVal" : self.memberVal,
                "productList" : self.productList
            }
            f.write(json.dumps(settingInit))
    
    def mainMenu(self):
        menubar = Menu(self.mainWin)
        self.mainWin.config(menu=menubar)

        option_menu = Menu(menubar,tearoff=0)
        option_menu.add_command(label='Product Adjustment', command=self.adjustProduct)
        option_menu.add_command(label='Tax/Service Charge Rate', command=self.tsRate)
        option_menu.add_command(label='Membership', command=self.memberManage)
        option_menu.add_separator()
        option_menu.add_command(label='Exit',command=self.mainWin.destroy)
        menubar.add_cascade(label="Options",menu=option_menu)

        help_menu = Menu(menubar,tearoff=0)
        help_menu.add_command(label='Income Summary', command=lambda:self.incomeSum(f"{os.path.dirname(os.path.abspath(__file__))}\{self.currentDate}.pickle"))
        help_menu.add_command(label='Membership Analysis', command=lambda:self.membershipUsage(f"{os.path.dirname(os.path.abspath(__file__))}\{self.currentDate}.pickle"))
        help_menu.add_command(label='Peak Time Analysis', command=lambda:self.peakTime(f"{os.path.dirname(os.path.abspath(__file__))}\{self.currentDate}.pickle"))
        menubar.add_cascade(label="More...",menu=help_menu)


    #Tax/Service Window
    def tsRate(self):
        self.tsRateWin = Toplevel(self.mainWin)
        self.tsRateWin.title("Tax & Service Charge Rate")

        frame1 = LabelFrame(self.tsRateWin, text="Enter Tax rate in %", padx=10, pady=10)
        frame1.pack(padx=10, pady=10)
        self.taxE = Entry(frame1, bd=5, width=35)
        self.taxE.pack()

        frame2 = LabelFrame(self.tsRateWin, text="Enter Service Charge rate in %", padx=10, pady=10)
        frame2.pack(padx=10, pady=10)
        self.serE = Entry(frame2, bd=5, width=35)
        self.serE.pack()

        Button(self.tsRateWin, text="Submit", command=self.setTSRate, padx=10).pack(pady=10, padx=2, side=RIGHT)
        
    def setTSRate(self):
        try:
            if self.taxE.get() == '':
                raise Exception
            self.taxRate = (float(self.taxE.get()) / 100) + 1
        except ValueError as e:
            messagebox.showerror("Invalid Value", "Enter the percentage for tax: \n" + str(e))
        except Exception:
            pass
            
        try:
            if self.serE.get() == '':
                raise Exception
            self.serRate = (float(self.serE.get()) / 100) + 1
        except ValueError as e:
            messagebox.showerror("Invalid Value", "Enter the percentage for service charge: \n" + str(e))
        except Exception:
            pass
            
        self.updateSettings()
        
    
    #Product Window
    def adjustProduct(self):
        self.adjustP = Toplevel(self.mainWin)
        self.adjustP.title("Product Adjustment")
        
        Label(self.adjustP, text="Product Adjustment\n").grid(row=0, column=0)
        
        self.adjPscrollbar = Scrollbar(self.adjustP)
        self.adjPscrollbar.grid(row=1, column=1, sticky=NS)
        self.displayList = Listbox(self.adjustP, yscrollcommand=self.adjPscrollbar.set)
        self.displayProductListbox()
        
        adjPFrame = LabelFrame(self.adjustP, text="Product Info", padx=10, pady=10)
        adjPFrame.grid(row=1, column=2, sticky=N)
        Label(adjPFrame, text="Name").grid(row=3, column=1, sticky=W)
        self.pName = Entry(adjPFrame, bd=5, width=40)
        self.pName.grid(row=4, column=1, columnspan=3)
        Label(adjPFrame, text="Price").grid(row=5, column=1, sticky=W)
        self.pPrice = Entry(adjPFrame, bd=5, width=40)
        self.pPrice.grid(row=6, column=1, columnspan=3)
        
        self.displayList.bind('<<ListboxSelect>>', self.productInfo)
        Button(adjPFrame, text="Delete", command=self.delProduct, padx=15).grid(row=7, column=2, padx=2, pady=2)
        Button(adjPFrame, text="Edit/New", command=self.newProduct, padx=15).grid(row=7, column=3, padx=2, pady=2)
    
    def displayProductListbox(self):
        self.displayList = Listbox(self.adjustP, yscrollcommand=self.adjPscrollbar.set )
        self.displayList.bind('<<ListboxSelect>>', self.productInfo)
        for key, val in self.productList.items():
            self.displayList.insert(END, key)
        self.displayList.grid(row=1, column=0)
        self.adjPscrollbar.config( command = self.displayList.yview )

    def productInfo(self, event):
        self.pName.delete(0, END)
        self.pName.insert(END, self.displayList.get(ANCHOR))

        self.pPrice.delete(0, END)
        self.pPrice.insert(END, self.productList.get(self.pName.get()))

    def newProduct(self):
        try:
            self.productList.update({self.pName.get() : int(self.pPrice.get())})
            self.displayProductListbox()
            
            self.updateSettings()
        except ValueError as e:
            messagebox.showerror("Invalid Value", "Enter an integer: \n" + str(e))

    def delProduct(self):
        try :
            self.productList.pop(self.pName.get())
            self.displayProductListbox()
            
            self.updateSettings()
        except KeyError as e:
            messagebox.showerror("Invalid Name", "Enter a correct product name:\n" + str(e) + " is not found")
    

    #Membership Window
    def memberManage(self):
        self.memWin = Toplevel(self.mainWin)
        self.memWin.title("Membership Management")
        self.memWin.geometry("750x400")
        
        regis = LabelFrame(self.memWin, text="Register New Member")
        regis.pack()
        self.registerEntry = Entry(regis, bd=5, width=35)
        self.registerEntry.pack()
        Button(regis, text="Register Silver Member", command=self.registerSilMember, pady=5, padx=10).pack(pady=10, padx=2, side=RIGHT)
        Button(regis, text="Register Gold Member", command=self.registerGoldMember, pady=5, padx=10).pack(pady=10, padx=2, side=RIGHT)
        Button(regis, text="Register Platinum Member", command=self.registerPlatMember, pady=5, padx=10).pack(pady=10, padx=2, side=RIGHT)

        mframe = LabelFrame(self.memWin)
        mframe.pack(side=LEFT)
        frame1 = LabelFrame(mframe, text="Silver Discount Rate %", padx=10, pady=5)
        frame1.pack(padx=10, pady=10, anchor=W)
        self.silDis = Entry(frame1, bd=5, width=35)
        self.silDis.pack()

        frame2 = LabelFrame(mframe, text="Gold Discount Rate %", padx=10, pady=5)
        frame2.pack(padx=10, pady=10, anchor=W)
        self.goldDis = Entry(frame2, bd=5, width=35)
        self.goldDis.pack()

        frame3 = LabelFrame(mframe, text="Platinum Discount Rate %", padx=10, pady=5)
        frame3.pack(padx=10, pady=10, anchor=W)
        self.platDis = Entry(frame3, bd=5, width=35)
        self.platDis.pack()
        Button(mframe, text="Confirm", command=self.setMemRate, padx=10).pack(pady=10, padx=2)
        
        self.memListText = Text(self.memWin, width=60, height=17)
        self.memListText.pack(anchor=E, side=RIGHT, padx=3, pady=2)
        
        self.updateMemList()
        
    
    def updateMemList(self):
        self.memListText.delete('1.0', END)
        self.memListText.insert(END, "\n====================== Members List ======================\n ")
        for i in self.memberList:
            self.memListText.insert(END, f" \n {i.id} \t\t{i.points:05d} points \t\t{i.__class__.__name__}")
    
    def registerSilMember(self):
        self.registerEntry.delete(0, END)
        generateNewMem = self.currentDate+str(self.memberOrder).zfill(4)
        self.memberList.append(membershipSilver(generateNewMem, self.memberVal.get("sil")))
        self.registerEntry.insert(END, generateNewMem)
        self.memberOrder += 1
        
        self.updateMemList()
        self.updateSettings()
            
    def registerGoldMember(self):
        self.registerEntry.delete(0, END)
        generateNewMem = self.currentDate+str(self.memberOrder).zfill(4)
        self.memberList.append(membershipGold(generateNewMem, self.memberVal.get("gold")))
        self.registerEntry.insert(END, generateNewMem)
        self.memberOrder += 1
        
        self.updateMemList()
        self.updateSettings()
        
    def registerPlatMember(self):
        self.registerEntry.delete(0, END)
        generateNewMem = self.currentDate+str(self.memberOrder).zfill(4)
        self.memberList.append(membershipPlatinum(generateNewMem, self.memberVal.get("plat")))
        self.registerEntry.insert(END, generateNewMem)
        self.memberOrder += 1
        
        self.updateMemList()
        self.updateSettings()
            
    def setMemRate(self):
        try:
            if self.silDis.get() == '':
                raise Exception
            self.memberVal.update({"sil" : 1.0 - float(self.silDis.get())/100})
        except ValueError as e:
            messagebox.showerror("Invalid Value", "Enter a percentage for silver: \n" + str(e))
        except Exception:
            pass
            
        try:
            if self.goldDis.get() == '':
                raise Exception
            self.memberVal.update({"gold" : 1.0 - float(self.goldDis.get())/100})
        except ValueError as e:
            messagebox.showerror("Invalid Value", "Enter a percentage for gold: \n" + str(e))
        except Exception:
            pass
        
        try:
            if self.platDis.get() == '':
                raise Exception
            self.memberVal.update({"plat" : 1.0 - float(self.platDis.get())/100})
        except ValueError as e:
            messagebox.showerror("Invalid Value", "Enter a percentage for platinum: \n" + str(e))
        except Exception:
            pass
            
        self.updateSettings()


    #Table Window
    def orderWin(self):
        self.welFrame.destroy()
        self.welPad.destroy()
        self.tablePad = Label(self.mainWin, text="\t  ", bg=self.bg, fg=self.fg, font=("Calibri", 15))
        self.tablePad.grid(row=0, column=0)
        self.orderWinLabel = Label(self.mainWin, text="Tables Management", bg=self.bg, fg=self.fg, font=("Calibri", 20))
        self.orderWinLabel.grid(row=0, column=1, padx=2, pady=2)
        
        self.tableNo = 1
        try:
            self.loadBill(f"{os.path.dirname(os.path.abspath(__file__))}\{self.currentDate}.pickle")
        except:
            self.orderNo = 1
        self.tableList = []

        try:
            if os.path.exists(f"{os.path.dirname(os.path.abspath(__file__))}\\tables.pickle"):
                raise Exception
        except:
            self.loadDraw = Button(self.mainWin, text="Load", command=self.loadTablepos, width=80, bg=self.bg, fg=self.fg, font=("Calibri", 20))
            self.loadDraw.grid(row=2, column=1, padx=2, pady=2)
          
        self.recallCanvas()
        self.doneDrawButton = Button(self.mainWin, text="Confirm", command=self.doneDraw, width=80, bg=self.bg, fg=self.fg, font=("Calibri", 20))

    def recallCanvas(self):
        self.orderWinLabel.config(text="Tables Management")
        self.canvasFrame = LabelFrame(self.mainWin)
        self.canvasFrame.grid(row=1, column=1, padx=2, pady=2)
        self.canvas = Canvas(self.canvasFrame, width=1100, height=600, bg=self.bg)
        self.canvas.pack()
        
        if len(self.tableList) == 0:
            self.canvas.bind('<Button-1>', self.draw)
        else:
            for i in self.tableList:
                self.canvas.create_rectangle(i.pos["x"]-40, i.pos["y"]-40, i.pos["x"]+40, i.pos["y"]+40, outline=self.fg, fill=self.sec, width=2)
                self.canvas.create_text(i.pos["x"], i.pos["y"], text="Table " + str(i.number), fill=self.fg, font=("Calibri", 12))
                self.doneDraw()

    def draw(self, click):
        if os.path.exists(f"{os.path.dirname(os.path.abspath(__file__))}\\tables.pickle"):
            self.loadDraw.destroy()
        self.doneDrawButton.grid(row=3, column=1, padx=2, pady=2)
        
        try:
            for i in self.tableList:
                if (click.x > i.pos.get("x") - 80 and click.x < i.pos.get("x") + 80) and (click.y > i.pos.get("y") - 80 and click.y < i.pos.get("y") + 80):
                    raise Exception
            self.canvas.create_rectangle(click.x-40, click.y-40, click.x+40, click.y+40, outline=self.fg, fill=self.sec, width=2)
            self.tableList.append(tableInfo(self.tableNo, {"x" : click.x, "y" : click.y}))
            self.canvas.create_text(click.x, click.y, text="Table " + str(self.tableNo), fill=self.fg, font=("Calibri", 12))
            self.tableNo += 1
        except:
            pass
            
    def doneDraw(self):
        self.canvas.unbind('<Button-1>')
        self.doneDrawButton.destroy()
        self.saveTablepos()
        
        self.canvas.bind('<Button-1>', self.tableOrder)
    
    def tableOrder(self, click):
        for i in self.tableList:
            if abs(click.x - int(i.pos["x"])) <= 40 and abs(click.y - int(i.pos["y"])) <= 40:
                i.order = self.orderNo
                self.canvasFrame.grid_forget()
                self.orderWinLabel.grid_forget()
                self.orderLabel = Label(self.mainWin, text="Table: " + str(i.number) + "\nOrder: " + str(self.orderNo), bg=self.bg, fg=self.fg, font=("Calibri", 15, font.BOLD))
                self.orderLabel.grid(row=1, column=1, padx=2, pady=2)
                
                self.billDetail = billInfo(self.orderNo, i.pos)
                self.menuDisplay()
                
                self.orderNo += 1

    def saveTablepos(self):
        with open(f"{os.path.dirname(os.path.abspath(__file__))}\\tables.pickle", 'wb') as f:
            pickle.dump(self.tableList, f)

    def loadTablepos(self):
        self.loadDraw.destroy()
        self.canvasFrame.grid_forget()
        
        with open(f"{os.path.dirname(os.path.abspath(__file__))}\\tables.pickle", 'rb') as f:
            self.tableList = pickle.load(f)

        self.recallCanvas()
    
    
    #Order Window
    def menuDisplay(self):
        self.orderDetail = dict()
        
        self.orderFrame = LabelFrame(self.mainWin, bg=self.bg, fg=self.fg)
        self.orderFrame.grid(row=2, column=1, padx=5, pady=5)
        self.orderScrollbar = Scrollbar(self.orderFrame, bg=self.bg)
        self.orderScrollbar.grid(row=2, rowspan=6, column=2, sticky=NS)
        self.displayMenu = Listbox(self.orderScrollbar, yscrollcommand=self.orderScrollbar.set)
        self.displayOrderListbox()
        self.displayMenu.bind('<<ListboxSelect>>', self.updateBillEntry)

        self.orderAmountFrame = LabelFrame(self.orderFrame, text="Amount", font=("Calibri", 13), bg=self.bg, fg=self.fg)
        self.orderAmountFrame.grid(row=2, column=3)
        self.orderAmount = Entry(self.orderAmountFrame, bd=3, width=15, font=15)
        self.orderAmount.pack()
        self.orderBack = Button(self.orderFrame, text="Enter", command=self.updateBill, width=15, height=5, font=("Calibri", 15), bg=self.bg, fg=self.fg)
        self.orderBack.grid(row=3, column=3, padx=2, pady=2, sticky=N)
        
        self.memFrame = LabelFrame(self.orderFrame, text="Membership ID: ", font=("Calibri", 13), bg=self.bg, fg=self.fg)
        self.memFrame.grid(row=4, column=3, padx=2, pady=2)
        self.enterMemID = Entry(self.memFrame, bd=3, width=15, font=15)
        self.enterMemID.pack()
        
        self.orderBack = Button(self.orderFrame, text="Confirm", command=self.endBill, width=15, height=5, font=("Calibri", 15), bg=self.bg, fg=self.fg)
        self.orderBack.grid(row=5, column=3, padx=2, pady=2, sticky=N)
        
        self.billHeader = Label(self.orderFrame, text="Order Summary", font=("Calibri", 13), bg=self.bg, fg=self.fg)
        self.billHeader.grid(row=1, column=4)
        self.billDisplay = Text(self.orderFrame, height=35, width=60)
        self.billDisplay.insert(END, " Menu\t\tAmount\t\tPrice\t\tSum\n\n")
        self.billDisplay.grid(row=2, column=4, padx=5, pady=5, rowspan=4)
    
    def endBill(self):
        self.billDetail.time = datetime.datetime.now().strftime('%H:%M:%S')
        self.billDetail.order = self.orderDetail
        total = 0
        for key, val in self.orderDetail.items():
            total+= int(self.productList.get(key))*val
        self.billDetail.total = total
        
        if self.enterMemID.get() == "":
            self.billDetail.membership = None
            self.billDetail.totalpp = total
            self.billDetail.totalpp *= self.serRate
            self.billDetail.totalpp *= self.taxRate
            self.billDetail.totalpp = round(self.billDetail.totalpp, 2)
        else:
            for i in self.memberList:
                if self.enterMemID.get() == str(i.id):
                    self.billDetail.membership = i.__class__.__name__
                    self.billDetail.totalpp = i.discountDeduction(total)
                    self.billDetail.totalpp *= self.serRate
                    self.billDetail.totalpp *= self.taxRate
                    self.billDetail.totalpp = round(self.billDetail.totalpp, 2)
                    i.points += self.billDetail.total * 0.1
                    
                    break
                else:
                    self.billDetail.totalpp = total
                    self.billDetail.totalpp *= self.serRate
                    self.billDetail.totalpp *= self.taxRate
                    self.billDetail.totalpp = round(self.billDetail.totalpp, 2)
            
        self.orderList.append(self.billDetail)
        self.orderFrame.grid_forget()
        
        self.saveBill()
        self.loadBill(f"{os.path.dirname(os.path.abspath(__file__))}\{self.currentDate}.pickle")
        self.orderBack.forget()
        self.recallCanvas()
    
    def displayOrderListbox(self):
        self.displayMenu = Listbox(self.orderFrame, yscrollcommand=self.orderScrollbar.set , height=22, width=35, font=30)
        for key, val in self.productList.items():
            self.displayMenu.insert(END, key)
        self.displayMenu.grid(row=2, column=0, columnspan=2, rowspan=4, sticky=E)
        self.orderScrollbar.config( command = self.displayMenu.yview )  
    
    def updateBillEntry(self, event):
        self.orderAmount.delete(0, END)
        selection = self.displayMenu.curselection()
        try:
            if self.orderDetail.get((self.displayMenu.get(selection))) is None:
                self.orderAmount.insert(END, "")
            else:
                self.orderAmount.insert(END, str(self.orderDetail.get((self.displayMenu.get(selection)))))
        except: 
            pass
    
    def updateBill(self):
        try:
            selection = self.displayMenu.curselection()
            self.orderDetail.update({self.displayMenu.get(selection) : int(self.orderAmount.get())})
            orderText = ""
            sum = 0.0
            
            self.billDisplay.delete('1.0', END)
            orderText = " Menu\t\tAmount\t\tPrice\t\tSum\n\n"
            for key, val in self.orderDetail.items():
                sum += int(self.productList.get(key))*val
                orderText += f" {key}\t\t{val}\t\t{int(self.productList.get(key))}\t\t{int(self.productList.get(key))*val}\n"
            orderText += f"\n \t\t\t\t\tTotal :\t{sum}\n \t\t\t\t\tNet   :\t{sum*self.serRate*self.taxRate:.2f}"
            self.billDisplay.insert(END, orderText)
        except ValueError as e:
            messagebox.showerror("Invalid Value", "Enter an integer: \n" + str(e))
        except:
            pass

    def saveBill(self):
        with open(f"{os.path.dirname(os.path.abspath(__file__))}\{self.currentDate}.pickle", 'wb') as f:
            pickle.dump(self.orderList, f)
    
    def loadBill(self, file):
        with open(file, 'rb') as f:
            self.orderList = pickle.load(f)
            self.orderNo = self.orderList[-1].number + 1
    
    #Analysis Function
    def incomeSum(self, file):
        try:
            self.loadBill(file)
            self.incomeStat = {"Net Total" : 0.0, "Total" : 0.0}

            for i in self.orderList:
                self.incomeStat["Total"] += i.total
                self.incomeStat["Net Total"] += i.totalpp
                        
            plt.bar(list(self.incomeStat.keys()), list(self.incomeStat.values()))
        
            plt.ylabel("Amount")
            plt.title("Income Summary")
            plt.show()
        except:
            messagebox.showerror("Data Not Found", "Database is empty")
    
    def preferredDish(self, file):
        try:
            self.loadBill(file)
            menu = dict()

            for i in self.orderList:
                for key, val in i.order.items():
                    if key in menu:
                        menu[key] = menu[key] + val
                    else:
                        menu.update({key : val})
            
            for i in self.productList.keys():
                if i not in menu.keys():
                    menu.update({i : 0})
            
            fig, ax = plt.subplots()
            ax.barh(list(menu.keys()), list(menu.values()))
            for s in ['top', 'bottom', 'left', 'right']:ax.spines[s].set_visible(False)
            
            ax.xaxis.set_ticks_position('none')
            ax.yaxis.set_ticks_position('none')
            
            ax.xaxis.set_tick_params(pad = 5)
            ax.yaxis.set_tick_params(pad = 10)
            
            ax.grid(b = True, color ='grey', linestyle ='-.', linewidth = 0.5, alpha = 0.2)
            ax.invert_yaxis()
            ax.set_title('Number of dishes ordered', loc ='left')
            
            plt.show()
        except Exception as e:
            messagebox.showerror("Error", "Failed to proceed :\n" + str(e))
 
    def peakTime(self, file):
        try:
            self.loadBill(file)
            self.timeStat = dict()
            
            for i in self.orderList:
                if i.time[:2] not in self.timeStat:
                    self.timeStat.update({i.time[:2] : 1})
                else:
                    self.timeStat.update({i.time[:2] : int(self.timeStat.get(i.time[:2])) + 1})
            
            plt.plot(self.timeStat.keys(), self.timeStat.values())
            plt.title('Peak Time Analysis')
            plt.xlabel('Time')
            plt.ylabel('Amount')
            plt.show()
        except:
            messagebox.showerror("Data Not Found", "Database is empty")
    
    def membershipUsage(self, file):
        try:
            self.loadBill(file)
            self.memberStat = {"None" : 0, "Silver" : 0, "Gold" : 0, "Platinum" : 0}
            for i in self.orderList:
                match i.membership:
                    case None:
                        self.memberStat["None"] += 1
                    case 'membershipSilver':
                        self.memberStat["Silver"] += 1
                    case 'membershipGold':
                        self.memberStat["Gold"] += 1
                    case 'membershipPlatinum':
                        self.memberStat["Platinum"] += 1

            fig1, ax1 = plt.subplots()
            ax1.pie(list(self.memberStat.values()), labels=list(self.memberStat.keys()), autopct='%1.1f%%', shadow=True, startangle=90)
            ax1.axis('equal')
            plt.title('Membership Analysis')
            plt.show()
        except:
            messagebox.showerror("Data Not Found", "Database is empty")

class membershipClass(ABC):

    def __init__(self, id, points=0):
        self.id = id
        self.points = points
    
    @abstractmethod
    def discountDeduction(self, total):
        pass

class membershipSilver(membershipClass):

    def __init__(self, id, discount, points=0):
        super().__init__(id, points)
        self.discount = discount

    def discountDeduction(self, total):
        return self.discount*total

class membershipGold(membershipClass):

    def __init__(self, id, discount, points=0):
        super().__init__(id, points)
        self.discount = discount

    def discountDeduction(self, total):
        return self.discount*total
    
class membershipPlatinum(membershipClass):

    def __init__(self, id, discount, points=0):
        super().__init__(id, points)
        self.discount = discount

    def discountDeduction(self, total):
        return self.discount*total
    
class tableInfo:
    
    def __init__(self, number, pos):
        self.number = number
        self.pos = pos

class billInfo(tableInfo):

    def __init__(self, number, pos):
        super().__init__(number, pos)
        self.order = None
        self.membership = None
        self.time = ""
        self.total = 0
        self.totalpp = 0

class Analysis(Main, Prompt):
    
    def __init__(self):
        self.anaWin = Tk()
        self.anaWin.title("Statistical Menu")
        self.anaWin.geometry("400x400")
        
        self.loadSettings()
        
        self.currentData = Label(self.anaWin, text="Current data: None", font=("Calibri", 12, font.BOLD))
        self.currentData.pack()
        
        self.open = Button(self.anaWin, text="Open", command=self.openFile, font=("Calibri", 10, font.BOLD))
        self.open.pack(padx=10, pady=10)
        self.incomeSumBut = Button(self.anaWin, text="Income Summary", command=lambda:self.incomeSum(self.filename), state=DISABLED, font=("Calibri", 10), padx=35, pady=2)
        self.incomeSumBut.pack(padx=10, pady=5)
        self.preferredDishBut = Button(self.anaWin, text="Ordering Statistic", command=lambda:self.preferredDish(self.filename), state=DISABLED, font=("Calibri", 10), padx=35, pady=2)
        self.preferredDishBut.pack(padx=10, pady=5)
        self.peakTimeBut = Button(self.anaWin, text="Peak-Time Analysis", command=lambda:self.peakTime(self.filename), state=DISABLED, font=("Calibri", 10), padx=30, pady=2)
        self.peakTimeBut.pack(padx=10, pady=5)
        self.membershipUsageBut = Button(self.anaWin, text="Membership Usage Statistic", command=lambda:self.membershipUsage(self.filename), state=DISABLED, font=("Calibri", 10), padx=8, pady=2)
        self.membershipUsageBut.pack(padx=10, pady=5)
        
        Label(self.anaWin, text="Enter the name of your company to enter Management Mode.", font=("Calibri", 10),).pack(padx=10, pady=10)
        self.prompt = Entry(self.anaWin, bd=5, width=35)
        self.prompt.pack()
        Button(self.anaWin, text="Management Mode", command=self.setName, font=("Calibri", 10), padx=8, pady=2).pack(padx=10, pady=5)
        Button(self.anaWin, text="Exit", command=self.anaWin.destroy, font=("Calibri", 10), padx=8, pady=2).pack(padx=10, pady=5)
        
        self.anaWin.mainloop()

    def openFile(self):
        try:
            self.filename = filedialog.askopenfilename(initialdir = f"{os.path.dirname(os.path.abspath(__file__))}",title = "Select a File",filetypes = (("pickle files","*.pickle*"),("all files","*.*")))
            self.loadBill(self.filename)
            self.currentData.config(text=f"Current data: {self.filename[-15:]}")
            
            self.incomeSumBut.config(state='normal')
            self.preferredDishBut.config(state='normal')
            self.membershipUsageBut.config(state='normal')
            self.peakTimeBut.config(state='normal')
        except:
            messagebox.showerror("Data Not Found", "Invalid file chosen")    

Prompt()
Editor is loading...