Tkinter Restaurant Billing System - Version 1

This is the first version of a restaurant billing project built with Python and Tkinter. The menu is stored in a Python dictionary. Each menu item has a quantity selector, and the selected items are added to a Treeview when the user generates the bill.

The program calculates the subtotal, adds a sample 10% tax and displays the final amount. The Reset button clears the invoice and prepares the interface for the next order.

Menu dictionary
      |
      v
Quantity selection
      |
      v
Generate Bill
      |
      +--> Treeview invoice rows
      +--> Subtotal
      +--> Tax
      +--> Final total
      |
      v
Reset

Restaurant Management Script using Tkinter to Generate Bills

Restaurant Billing Project Features 🔝

  1. Store menu items and their unit prices in a Python dictionary.
  2. Display the available food items in the Tkinter interface.
  3. Use a Spinbox to select the quantity of each item.
  4. Generate invoice rows only for items whose quantity is greater than zero.
  5. Display item name, unit price, quantity and line total in Treeview.
  6. Calculate the subtotal of all selected items.
  7. Add a sample 10% tax.
  8. Display the final bill total.
  9. Reset all quantities and invoice data for the next order.
  10. Optionally add a background image and individual food-item images.

The first version does not need a database. Each menu item can be stored in a dictionary.

menu={
    0:{'name':'Item One','price':Decimal('20.00')},
    1:{'name':'Item Two','price':Decimal('40.00')},
    2:{'name':'Item Three','price':Decimal('30.00')}
}

Each dictionary entry contains:

  • name: text shown to the user.
  • price: price for one unit.

Using named fields such as name and price makes the data easier to understand than relying on positions such as menu[i][0] and menu[i][1].

Why Use Decimal for Prices?

Python Decimal provides fixed decimal arithmetic that is more suitable for currency-style calculations than binary floating-point values.

from decimal import Decimal

price=Decimal('20.00')

Create the Tkinter Layout 🔝

The window uses two main sections:

  • Left: menu items and quantity selectors.
  • Right: generated invoice and totals.
root=tk.Tk()
root.geometry('1000x650')
root.title('Restaurant Billing System - plus2net')

root.columnconfigure(0,weight=3)
root.columnconfigure(1,weight=2)
root.rowconfigure(0,weight=1)

Generate Menu Controls from the Dictionary 🔝

Instead of manually creating eight separate buttons and eight separate Spinboxes, we can create the controls in a loop.

quantity_vars={}

for index,item in menu.items():
    row=index//4
    column=index%4

    card=ttk.Frame(menu_frame,padding=8)
    card.grid(row=row,column=column,padx=8,pady=8,sticky='nsew')

    ttk.Label(card,text=item['name']).grid(row=0,column=0)
    ttk.Label(card,text=f"Price: {item['price']:.2f}").grid(row=1,column=0)

    quantity_vars[index]=tk.IntVar(value=0)

    spin=tk.Spinbox(
        card,
        from_=0,
        to=10,
        width=4,
        textvariable=quantity_vars[index],
        state='readonly'
    )
    spin.grid(row=2,column=0,pady=5)

This design is easier to maintain. Adding another menu item to the dictionary automatically adds another control to the interface.

Create the Invoice Treeview 🔝

The invoice is flat tabular data, so we can use named Treeview columns.

tree=ttk.Treeview(
    bill_frame,
    columns=('item','price','qty','total'),
    show='headings',
    height=12
)

The columns represent:

Item | Price | Quantity | Total

The final column contains:

quantity * unit price

Generate the Restaurant Bill 🔝

When the user clicks Get Bill, the program first removes any previously generated invoice rows.

for row in tree.get_children():
    tree.delete(row)

Then it checks every menu quantity:

for index,item in menu.items():
    qty=quantity_vars[index].get()

    if qty>0:
        line_total=(item['price']*qty).quantize(MONEY)
        subtotal+=line_total

Only ordered items are added to Treeview.

tree.insert(
    '',
    tk.END,
    values=(
        item['name'],
        f"{item['price']:.2f}",
        qty,
        f"{line_total:.2f}"
    )
)

Calculate Tax and Final Total

This tutorial uses a sample 10% tax rate.

TAX_RATE=Decimal('0.10')

tax=(subtotal*TAX_RATE).quantize(MONEY)
final_total=(subtotal+tax).quantize(MONEY)

Reset the Billing System 🔝

The older version created new IntVar objects and reconfigured every Spinbox during reset. That is unnecessary.

Keep the original variables and set them back to zero:

for qty_var in quantity_vars.values():
    qty_var.set(0)

Then clear the Treeview and totals:

subtotal_var.set('0.00')
tax_var.set('0.00')
total_var.set('0.00')

Complete Tkinter Restaurant Billing Program 🔝

import tkinter as tk
from tkinter import ttk
from decimal import Decimal, ROUND_HALF_UP

MONEY=Decimal('0.01')
TAX_RATE=Decimal('0.10')

menu={
    0:{'name':'Item One','price':Decimal('20.00')},
    1:{'name':'Item Two','price':Decimal('40.00')},
    2:{'name':'Item Three','price':Decimal('30.00')},
    3:{'name':'Item Four','price':Decimal('20.00')},
    4:{'name':'Item Five','price':Decimal('30.00')},
    5:{'name':'Item Six','price':Decimal('20.00')},
    6:{'name':'Item Seven','price':Decimal('40.00')},
    7:{'name':'Item Eight','price':Decimal('30.00')}
}

root=tk.Tk()
root.geometry('1000x650')
root.minsize(850,550)
root.title('Restaurant Billing System - plus2net')

root.columnconfigure(0,weight=3)
root.columnconfigure(1,weight=2)
root.rowconfigure(0,weight=1)

menu_frame=ttk.Frame(root,padding=10)
menu_frame.grid(row=0,column=0,sticky='nsew')

bill_frame=ttk.Frame(root,padding=10)
bill_frame.grid(row=0,column=1,sticky='nsew')
bill_frame.rowconfigure(1,weight=1)
bill_frame.columnconfigure(0,weight=1)

for column in range(4):
    menu_frame.columnconfigure(column,weight=1)

ttk.Label(menu_frame,text='Menu',font=('Times',22,'bold')).grid(row=0,column=0,columnspan=4,pady=(0,12))

quantity_vars={}

for index,item in menu.items():
    row=index//4+1
    column=index%4

    card=ttk.Frame(menu_frame,padding=8,relief='ridge')
    card.grid(row=row,column=column,padx=8,pady=8,sticky='nsew')

    ttk.Label(card,text=item['name'],font=('Times',13,'bold')).grid(row=0,column=0,pady=4)
    ttk.Label(card,text=f"Price: {item['price']:.2f}").grid(row=1,column=0,pady=4)

    quantity_vars[index]=tk.IntVar(value=0)
    spin=tk.Spinbox(card,from_=0,to=10,width=4,textvariable=quantity_vars[index],state='readonly')
    spin.grid(row=2,column=0,pady=6)

button_frame=ttk.Frame(menu_frame)
button_frame.grid(row=3,column=0,columnspan=4,pady=15)

ttk.Label(bill_frame,text='Bill',font=('Times',22,'bold')).grid(row=0,column=0,sticky='w',pady=(0,8))

tree=ttk.Treeview(bill_frame,columns=('item','price','qty','total'),show='headings',height=12)
tree.grid(row=1,column=0,sticky='nsew')

ys=ttk.Scrollbar(bill_frame,orient='vertical',command=tree.yview)
ys.grid(row=1,column=1,sticky='ns')
tree.configure(yscrollcommand=ys.set)

tree.heading('item',text='Item')
tree.heading('price',text='Price')
tree.heading('qty',text='Qty')
tree.heading('total',text='Total')

tree.column('item',width=140,anchor='w')
tree.column('price',width=75,anchor='e')
tree.column('qty',width=55,anchor='center')
tree.column('total',width=85,anchor='e')

subtotal_var=tk.StringVar(value='0.00')
tax_var=tk.StringVar(value='0.00')
total_var=tk.StringVar(value='0.00')

totals=ttk.Frame(bill_frame,padding=(0,12))
totals.grid(row=2,column=0,sticky='e')

ttk.Label(totals,text='Subtotal:').grid(row=0,column=0,sticky='e',padx=5)
ttk.Label(totals,textvariable=subtotal_var).grid(row=0,column=1,sticky='e')

ttk.Label(totals,text='Tax 10%:').grid(row=1,column=0,sticky='e',padx=5)
ttk.Label(totals,textvariable=tax_var).grid(row=1,column=1,sticky='e')

ttk.Label(totals,text='Final Total:',font=('Times',16,'bold')).grid(row=2,column=0,sticky='e',padx=5,pady=6)
ttk.Label(totals,textvariable=total_var,font=('Times',16,'bold')).grid(row=2,column=1,sticky='e')

def my_bill():
    subtotal=Decimal('0.00')

    for row in tree.get_children():
        tree.delete(row)

    for index,item in menu.items():
        qty=quantity_vars[index].get()

        if qty>0:
            line_total=(item['price']*qty).quantize(MONEY,rounding=ROUND_HALF_UP)
            subtotal+=line_total
            tree.insert('',tk.END,values=(item['name'],f"{item['price']:.2f}",qty,f"{line_total:.2f}"))

    subtotal=subtotal.quantize(MONEY,rounding=ROUND_HALF_UP)
    tax=(subtotal*TAX_RATE).quantize(MONEY,rounding=ROUND_HALF_UP)
    final_total=(subtotal+tax).quantize(MONEY,rounding=ROUND_HALF_UP)

    subtotal_var.set(f'{subtotal:.2f}')
    tax_var.set(f'{tax:.2f}')
    total_var.set(f'{final_total:.2f}')

def my_reset():
    for qty_var in quantity_vars.values():
        qty_var.set(0)

    for row in tree.get_children():
        tree.delete(row)

    subtotal_var.set('0.00')
    tax_var.set('0.00')
    total_var.set('0.00')

ttk.Button(button_frame,text='Get Bill',command=my_bill).grid(row=0,column=0,padx=8)
ttk.Button(button_frame,text='Reset',command=my_reset).grid(row=0,column=1,padx=8)

root.mainloop()

Adding Food and Background Images 🔝

The original project contains commented image code. Images can still be added, but avoid an absolute machine-specific path such as:

G:\My Drive\testing\plus2_restaurant_v1\images\

Keep the images inside the project folder instead:

item_image=tk.PhotoImage(file='images/food-item-1.png')

Then place the image in a Label or Button:

item_button=tk.Button(card,image=item_image,text='Item One',compound='top')
PhotoImage reference: Keep a Python reference to every PhotoImage object while it is displayed. Otherwise Tkinter may remove the image even though the widget still exists.

Version 2: Move Menu Data to a Database 🔝

Version 1 keeps the menu directly inside Python:

menu={
    0:{'name':'Item One','price':Decimal('20.00')}
}

This is useful for understanding the GUI and billing logic first.

In Restaurant Management V-2, the product data is moved to MySQL. That allows menu items, prices, categories and availability to be maintained independently of the GUI source code.

Frequently Asked Questions 🔝

Q1: Why store restaurant items in a dictionary?

A dictionary keeps the menu data separate from the widget code. The interface can loop through the dictionary to create menu controls automatically.

Q2: Why use Spinbox for quantity?

A Spinbox gives the user a controlled numeric choice and avoids typing a separate quantity for every menu item.

Q3: Why use Treeview for the bill?

Treeview displays the ordered products in rows and columns, making the invoice easier to read.

Q4: Why use Decimal for prices?

Decimal provides fixed decimal arithmetic and is more appropriate for currency-style calculations than binary floating-point values.

Q5: What does the Reset button do?

It clears all selected quantities, removes invoice rows and sets subtotal, tax and final total back to zero.

Q6: Where is the menu stored in Version 2?

Version 2 moves the product and price data to a database so the menu can be managed without editing the Python source.

Restaurant Management V-2 - Database Integration Restaurant Management V-3 Combobox for Item Selection Day-wise Report Installing Tables Edit and Update Product Table

More Projects using Tkinter


Subscribe to our YouTube Channel here



plus2net.com







Python Video Tutorials
Python SQLite Video Tutorials
Python MySQL Video Tutorials
Python Tkinter Video Tutorials
We use cookies to improve your browsing experience. . Learn more
HTML MySQL PHP JavaScript ASP Photoshop Articles Contact us
©2000-2026   plus2net.com   All rights reserved worldwide Privacy Policy Disclaimer