Invoice Generator with Python

Upgrade Your Skills, Upgrade Your Career - Learn more

Containing all the information about a buyer, seller, product, payments done for the product, and Invoice is a document that forms a contract between the dealers. We will be building a project for invoice generator using python and save it in the device given the required inputs in this project. So, let’s get started with it.

What is an Invoice Generator?

An invoice generator is a project that takes the inputs like company name, address, city, date, etc. via an interface. And then generates an invoice with the provided information and saves it in the form of a PDF.

Invoice Generator with Python

In this project, we will be using the Tkinter module to build the GUI (Graphical User Interface) where the inputs are taken, reportlab library to create a PDF and save it.

Download the Invoice Generator Python Project

You can download the Invoice generator with the Python project using the link: Invoice Generator Project

Project Prerequisites

It is expected that the developer has prior knowledge of Python and the Tkinter module. The above mentioned modules can be installed using the below commands.

pip install tk
pip install reportlab

Project Structure

We will be following the below steps to build the project:

  • Import the required modules
  • Build a GUI to take inputs
  • Write a function to choose the date and upload the signature
  • Write a function to generate an invoice and save it

Import the required modules

import os
import tkinter as tk
from tkinter import *
from reportlab.pdfgen import canvas
from tkinter import filedialog
from tkcalendar import Calendar

Code explanation:

In this part of the code, we import the above specified modules, tkinter, and reportlab. We also use the Calender object from tkcalender and os module to access files on device.

Build a GUI to take inputs

wn = Tk()
wn.title("Python Invoice Generator By PythonGeeks")
wn.geometry("750x800")
wn.configure(bg='azure2')


# creating wn in window
Label( wn,text="Enter your company details ",font=("calibre",30,"bold"),bg="azure2",fg="green").place(x=100,y=10)
Label( wn, text="Company Name", font=("calibre", 15), bg="azure2", fg="gray").place(x=50, y=80)

company_name=Entry( wn,font=("calibre",15))
company_name.place(x=270,y=80,width=300,height=35)
Label( wn, text="Address", font=("calibre", 15), bg="azure2", fg="gray").place(x=50, y=140)

address= Entry( wn, font=("calibre", 15))
address.place(x=270, y=140, width=300,height=35)
Label( wn, text="City", font=("calibre", 15), bg="azure2", fg="gray").place(x=50, y=200)

city = Entry( wn, font=("calibre", 15))
city.place(x=270, y=200, width=300, height=35)
Label( wn, text="GST Number", font=("calibre", 15), bg="azure2", fg="gray").place(x=50, y=260)

gstNo = Entry( wn, font=("calibre", 15))
gstNo.place(x=270, y=260, width=300, height=35)
Label( wn, text="Date", font=("calibre", 15), bg="azure2", fg="gray").place(x=50, y=320)

date = Label(wn, text = "",font=("calibre", 15))
date.place(x=270, y=320, width=300, height=35)
Button( wn, text="Select Date", font=("calibre", 14), command= selectDate).place(x=620, y=320)
Label( wn, text="Phone No", font=("calibre", 15), bg="azure2", fg="gray").place(x=50, y=380)

phNo = Entry( wn, font=("calibre", 15))
phNo.place(x=270, y=380, width=300, height=35)
Label( wn, text="Customer Name", font=("calibre", 15), bg="azure2", fg="gray").place(x=50, y=440)

c_name = Entry( wn, font=("calibre", 15))
c_name.place(x=270, y=440, width=300, height=35)
Label( wn, text="Authorized Signatory", font=("calibre", 15), bg="azure2", fg="gray").place(x=50, y=500)

auSign = Entry( wn, font=("calibre", 15))
auSign.place(x=270, y=500, width=300, height=35)
Label( wn, text="Company Image", font=("calibre", 15), bg="azure2", fg="gray").place(x=50, y=560)


# ==== Browse File
Button( wn, text="Browse Files", font=("calibre", 14), command= browseFiles).place(x=270, y=560)


# ====submit details
Button( wn, text = "Submit Details",command =  generateInvoice, font = ("calibre", 14),cursor = "hand2").place(x = 50, y = 640, width = 180, height = 40)
wn.mainloop()

Code explanation:

In this code we create a GUI for taking the required inputs

  • title(): It displays the title on the top of the GUI.
  • config(): It sets the background color of the GUI.
  • geometry(): It sets the length and width of the GUI.
  • place(): This is used to locate the widgets in a particular position based on coordinates mentioned.
  • Label(): This creates a label to show text on GUI.
  • Button(): This creates a button with mentioned properties and the command parameter represents the function that executed on pressing the button.
  • mainloop(): This makes sure the screen runs till the user manually closes the window.

Write a function to choose the date and upload the signature

def browseFiles():
    global wn,file_name
    file_name = filedialog.askopenfilename(title="Select your File")
    Label(wn, text=os.path.basename(file_name), font=("calibre", 15)).place(x=270, y=600)

def selectDate():

    global date
    root = Tk()
    root.geometry("400x400")

    # Adding Calendar
    cal = Calendar(root, selectmode = 'day',
                year = 2020, month = 5,
                day = 22)

    cal.pack(pady = 20)
    def grad_date():
        date.config(text = str(cal.get_date()))
        root.quit()
    Button(root, text = "Get Date",
        command = grad_date).pack(pady = 20)
    root.mainloop()

Code explanation:

Here, browseFiles() is used to select a file for setting the logo

  • askopenfilename() function opens a separate window to choose a file from device
  • .path.basename() is used to get the location of the file selected

selectDate() is used to choose a date

  • Here we firstcreate a window called root
  • Then we create a Calendar() object
  • Then give a button to return the date selected

Write a function to generate an invoice and save it

def generateInvoice():
    global file_name, company_name, address, city, gstNo, date, c_name, phNo, auSign
    inv_canvas = canvas.Canvas("Invoice Generated by PythonGeeks.pdf", pagesize=(200, 250), bottomup=0)

    inv_canvas.line(5, 45, 195, 45)
    inv_canvas.line(15, 120, 185, 120)
    inv_canvas.line(35, 108, 35, 220)
    inv_canvas.line(115, 108, 115, 220)
    inv_canvas.line(135, 108, 135, 220)
    inv_canvas.line(160, 108, 160, 220)
    inv_canvas.line(15, 220, 185, 220)

    inv_canvas.translate(10, 40)
    inv_canvas.scale(1, -1)
    inv_canvas.drawImage(file_name, 0, 0, width=50, height=30)
    inv_canvas.scale(1, -1)
    inv_canvas.translate(-10, -40)
    inv_canvas.setFont("Times-Bold", 10)
    inv_canvas.drawCentredString(125, 20, company_name.get())
    inv_canvas.setFont("Times-Bold", 5)
    inv_canvas.drawCentredString(125, 30, address.get())
    inv_canvas.drawCentredString(125, 35, city.get() + ", India")
    inv_canvas.setFont("Times-Bold", 6)
    inv_canvas.drawCentredString(125, 42, "GST No:"+gstNo.get())
    inv_canvas.setFont("Times-Bold", 8)
    inv_canvas.drawCentredString(100, 55, "INVOICE")
    inv_canvas.setFont("Times-Bold", 5)
    inv_canvas.drawRightString(70, 70, "Invoice No. :")
    inv_canvas.drawRightString(100, 70, "XXXXXXX")
    inv_canvas.drawRightString(70, 80, "Customer Name :")
    inv_canvas.drawRightString(100, 80, c_name.get() )
    inv_canvas.drawRightString(70, 90, "Date :")
    inv_canvas.drawRightString(100, 90, date.cget("text"))
    inv_canvas.drawRightString(70, 100, "Phone No. :")
    inv_canvas.drawRightString(100, 100, phNo.get())

    inv_canvas.roundRect(15, 108, 170, 130, 10, fill=0)

    inv_canvas.drawCentredString(25, 118, "S.No.")
    inv_canvas.drawCentredString(75, 118, "Orders")
    inv_canvas.drawCentredString(125, 118, "Price")
    inv_canvas.drawCentredString(148, 118, "Qty.")
    inv_canvas.drawCentredString(173, 118, "Total")

    inv_canvas.drawRightString(180, 228, auSign.get())
    inv_canvas.drawRightString(180, 235, "Signature")
    inv_canvas.showPage()
    inv_canvas.save()

Code explanation:

  • This function creates an invoice and saves it as a PDF
  • In this, we first created a Canvas and stared adding components to it
  • line() draws a line starting and ending at specified coordinated
  • translate() moves the position of the reference point from which coordinates are set
  • drawImage() places an image on the canvas
  • drawCentredString() writes specified text at specified position, center aligned
  • setfont() sets the font style and size of the text
  • drawRightString() writes text eight aligned
  • roundRect() draws a rectangle with rounded corners
  • save() saves the invoice as a PDF

Output of the Python Invoice Generator

Image of the GUI

python invoice generator output

Image of the Invoice PDF

invoice pdf

Conclusion

Hurray! We have completed building the Invoice generator using Python. We got to use different modules including Tkinter, and reportlab. Hope you enjoyed building with us!

Your 15 seconds will encourage us to work even harder
Please share your happy experience on Google | Facebook


PythonGeeks Team

The PythonGeeks Team offers industry-relevant Python programming tutorials, from web development to AI, ML and Data Science. With a focus on simplicity, we help learners of all backgrounds build their coding skills.

3 Responses

  1. priti jondhale says:

    how to run it

  2. faheem says:

    import os
    from tkinter import Tk, Label, Button, Entry, filedialog
    from tkinter import Toplevel
    from reportlab.pdfgen import canvas
    from tkcalendar import Calendar

    def browseFiles():
    global file_name
    file_name = filedialog.askopenfilename(title=”Select your File”)
    Label(wn, text=os.path.basename(file_name), font=(“calibre”, 15)).place(x=270, y=600)

    from reportlab.lib.pagesizes import letter # for letter size (8.5 x 11 inches)
    from reportlab.lib.pagesizes import A4 # for A4 size

    def generateInvoice():
    global file_name, company_name, address, city, gstNo, date, c_name, phNo, auSign
    # Change canvas size to A4 or letter size
    inv_canvas = canvas.Canvas(“Invoice Generated by faheem.pdf”, pagesize=A4, bottomup=0)

    # Adjusting margins and positioning
    margin_left = 0
    margin_top = 0
    width, height = A4 # Get A4 paper size dimensions

    inv_canvas.setFont(“Times-Bold”, 10)
    inv_canvas.drawCentredString(width / 2, margin_top, company_name.get())
    inv_canvas.setFont(“Times-Bold”, 6)
    inv_canvas.drawCentredString(width / 2, margin_top + 15, address.get())
    inv_canvas.drawCentredString(width / 2, margin_top + 20, city.get() + “, India”)
    inv_canvas.drawCentredString(width / 2, margin_top + 25, “GST No: ” + gstNo.get())
    inv_canvas.setFont(“Times-Bold”, 8)
    inv_canvas.drawCentredString(width / 2, margin_top + 40, “INVOICE”)

    # Adjusting text and element positions
    inv_canvas.setFont(“Times-Bold”, 5)
    inv_canvas.drawRightString(width – margin_left, margin_top + 60, “Invoice No. :”)
    inv_canvas.drawRightString(width – margin_left, margin_top + 70, “XXXXXXX”)
    inv_canvas.drawRightString(width – margin_left, margin_top + 80, “Customer Name :”)
    inv_canvas.drawRightString(width – margin_left, margin_top + 90, c_name.get())
    inv_canvas.drawRightString(width – margin_left, margin_top + 100, “Date :”)
    inv_canvas.drawRightString(width – margin_left, margin_top + 110, date.cget(“text”))
    inv_canvas.drawRightString(width – margin_left, margin_top + 120, “Phone No. :”)
    inv_canvas.drawRightString(width – margin_left, margin_top + 130, phNo.get())

    inv_canvas.roundRect(margin_left, margin_top + 130, width – 2 * margin_left, height – margin_top – 150, 10, fill=0)

    # Adjust the table layout
    inv_canvas.drawCentredString(margin_left + 10, margin_top + 150, “S.No.”)
    inv_canvas.drawCentredString(margin_left + 60, margin_top + 150, “Orders”)
    inv_canvas.drawCentredString(margin_left + 110, margin_top + 150, “Price”)
    inv_canvas.drawCentredString(margin_left + 140, margin_top + 150, “Qty.”)
    inv_canvas.drawCentredString(margin_left + 170, margin_top + 150, “Total”)

    inv_canvas.drawRightString(width – margin_left, margin_top + height – 80, auSign.get())
    inv_canvas.drawRightString(width – margin_left, margin_top + height – 70, “Signature”)

    inv_canvas.showPage()
    inv_canvas.save()

    def selectDate():
    top = Toplevel(wn)
    cal = Calendar(top, selectmode=’day’, year=2023, month=10, day=5)
    cal.pack(pady=20)

    def grab_date():
    date.config(text=cal.get_date())
    top.destroy()

    Button(top, text=”Select”, command=grab_date).pack(pady=20)

    # Setting up the main window
    wn = Tk()
    wn.title(” “)
    wn.geometry(“750×800″)
    wn.configure(bg=’azure2′)

    Label(wn, text=”Enter your company details”, font=(“calibre”, 30, “bold”), bg=”azure2″, fg=”green”).place(x=100, y=10)
    Label(wn, text=”Company Name”, font=(“calibre”, 15), bg=”azure2″, fg=”gray”).place(x=50, y=80)

    company_name = Entry(wn, font=(“calibre”, 15))
    company_name.place(x=270, y=80, width=300, height=35)
    Label(wn, text=”Address”, font=(“calibre”, 15), bg=”azure2″, fg=”gray”).place(x=50, y=140)

    address = Entry(wn, font=(“calibre”, 15))
    address.place(x=270, y=140, width=300, height=35)
    Label(wn, text=”City”, font=(“calibre”, 15), bg=”azure2″, fg=”gray”).place(x=50, y=200)

    city = Entry(wn, font=(“calibre”, 15))
    city.place(x=270, y=200, width=300, height=35)
    Label(wn, text=”GST Number”, font=(“calibre”, 15), bg=”azure2″, fg=”gray”).place(x=50, y=260)

    gstNo = Entry(wn, font=(“calibre”, 15))
    gstNo.place(x=270, y=260, width=300, height=35)
    Label(wn, text=”Date”, font=(“calibre”, 15), bg=”azure2″, fg=”gray”).place(x=50, y=320)

    date = Label(wn, text=””, font=(“calibre”, 15))
    date.place(x=270, y=320, width=300, height=35)

    Button(wn, text=”Select Date”, font=(“calibre”, 14), command=selectDate).place(x=620, y=320)

    Label(wn, text=”Phone No”, font=(“calibre”, 15), bg=”azure2″, fg=”gray”).place(x=50, y=380)

    phNo = Entry(wn, font=(“calibre”, 15))
    phNo.place(x=270, y=380, width=300, height=35)

    Label(wn, text=”Customer Name”, font=(“calibre”, 15), bg=”azure2″, fg=”gray”).place(x=50, y=440)

    c_name = Entry(wn, font=(“calibre”, 15))
    c_name.place(x=270, y=440, width=300, height=35)

    Label(wn, text=”Authorized Signatory”, font=(“calibre”, 15), bg=”azure2″, fg=”gray”).place(x=50, y=500)

    auSign = Entry(wn, font=(“calibre”, 15))
    auSign.place(x=270, y=500, width=300, height=35)

    Label(wn, text=”Company Image”, font=(“calibre”, 15), bg=”azure2″, fg=”gray”).place(x=50, y=560)

    # Browse button to select the company image
    Button(wn, text=”Browse”, font=(“calibre”, 14), command=browseFiles).place(x=270, y=560)

    # Submit button to generate invoice
    Button(wn, text=”Submit Details”, command=generateInvoice, font=(“calibre”, 14), cursor=”hand2″).place(x=50, y=640, width=180, height=40)

    wn.mainloop()

Leave a Reply

Your email address will not be published. Required fields are marked *