LambdaLabTM
Computer Science · Class 12 Project · Subject Code 083
Sample ProjectPython File Handling⏱️ 12 min read

GST Invoice Maker for a Small Shop

Turn a day's raw transactions into a tax invoice grouped by GST rate.

1Introduction: the problem it solves

Walk into any small shop and ask how the GST return gets filed. In most cases the answer is a notebook, a calculator and an evening lost at the end of every month. The shopkeeper writes each sale down, and then has to sort those sales by tax rate before anything can be claimed.

The sorting is the part a computer should be doing. The shop already has the data — it is just in the wrong shape.

who would use it

A kirana shop, a stationery shop, or any small trader who files GST returns.

Why it is worth computerising

The work being replaced is not difficult; it is repetitive, and that is what makes it error-prone. Every sale has to be written down, every written line has to be found again at the end of the month, and each one has to be put under the right tax rate before a single figure can be claimed. A shop doing forty sales a day is sorting twelve hundred lines by hand every month.

A mistake in that sorting is not caught by anybody. The total still looks like a total. It is only questioned if the return is scrutinised, by which time the mistake is months old. A program does the same sorting the same way every time, and takes a second over it, which is why this job is worth computerising even in a shop that is otherwise entirely on paper.

Objectives

  1. To replace the shopkeeper's handwritten day book with a file the computer can read
  2. To group a day's sales by GST rate automatically, which is the form the return demands
  3. To calculate the tax under each rate and the grand total without arithmetic by hand
  4. To produce a printable invoice that can be handed to a customer or filed for the return
  5. To keep the tax rates in one place, so a change in the law is a one-line edit

2How the job is done today

Before writing anything it is worth asking how the work is handled at present, and why each of those answers falls short. These were examined:

Manual day book and calculator

What most small shops actually use. It costs nothing and works, but the month-end sorting by tax rate is slow and a single mis-added column changes what is claimed.

Commercial billing software

Full-featured, and priced and shaped for shops much larger than a corner kirana. Most of what it does is never used, and the shopkeeper must learn its way of working.

Spreadsheet with formulas

A real step up, and common. It breaks down when the categories change or a formula is dragged one row short, and it cannot produce a formatted invoice by itself.

3Functionalities

  • Reads the day's sales from a plain CSV file the shopkeeper can type in any spreadsheet
  • Looks up the GST rate for each item's category (5%, 12% or 18%)
  • Groups the taxable value under each rate, which is exactly how the return wants it
  • Works out CGST/SGST totals and the grand total
  • Writes a printable invoice to a text file, not just to the screen

The functions that provide them

FunctionArgumentsWhat it does
read_sales()filenameRead the day's raw transactions from a CSV file.
group_by_rate()rowsAdd up the taxable value under each GST rate.
write_invoice()rows, totals, filenameWrite the finished invoice out as a text file, ready to print.

4Technical details

LanguagePython 3
StoragePlain text and CSV files
Modules used
  • csv — to read the transactions file without splitting strings by hand
  • datetime — for the invoice date
  • Text file handling — the invoice is written with open() and write()

5How the data is stored

Two files. `sales.csv` is the input the shop types, one row per sale. `invoice.txt` is what the program produces. Keeping the input as CSV matters: the shopkeeper can edit it in any spreadsheet without touching Python.

sales.csv — the input, one row per sale

FieldTypeDescription
itemtextName of the item sold, as it should appear on the invoice
categorytextgrocery, stationery or electronics — decides the GST rate
qtyintegerHow many units were sold
pricedecimalPrice of one unit, before tax

invoice.txt — the output

FieldTypeDescription
Item linestextOne line per sale: item, quantity, rate and amount in fixed columns
Rate blockstextTaxable value and GST under each of the 5%, 12% and 18% slabs
TotalstextTaxable value, total GST and the grand total

Sample contents of sales.csv

itemcategoryqtyprice
Rice 5kggrocery2310.00
Notebookstationery1045.00
Pen boxstationery3120.00
Table fanelectronics11450.00

6How it works, step by step

1
Read

read_sales() opens sales.csv and turns each row into a dictionary, converting qty to int and price to float.

2
Group

group_by_rate() looks up each item's category in the RATES table and adds its value to that rate's running total.

3
Calculate

For each rate, tax = taxable value x rate / 100. The totals are added up for the grand total.

4
Write

write_invoice() formats everything with str.format() column widths and writes it to invoice.txt.

7Source code

gst_invoice.py
# ---------------------------------------------------------------------------
# gst_invoice.py
#
# Reads a day's sales from a CSV file, groups them by GST rate, works out the
# tax under each rate, and writes a printable tax invoice to a text file.
#
# The shop types its sales into sales.csv using any spreadsheet. The program
# never asks the shopkeeper to learn anything new.
# ---------------------------------------------------------------------------

import csv                     # for reading sales.csv without splitting strings by hand
from datetime import date      # for putting today's date on the invoice

# The GST rate that applies to each category of goods. Keeping it here, in one
# place, means a change in the law is a one-line edit rather than a hunt
# through the program.
RATES = {"grocery": 5, "stationery": 12, "electronics": 18}


def read_sales(filename):
    """Read the day's raw transactions from a CSV file."""
    rows = []                                   # every sale will be collected here

    # newline="" is what the csv module asks for; it stops blank lines appearing
    # on Windows.
    with open(filename, "r", newline="") as f:
        # DictReader uses the first line of the file as the column names, so a
        # row arrives as {"item": "Rice 5kg", "category": "grocery", ...}
        for row in csv.DictReader(f):
            # Everything read from a file is text, so the two numeric columns
            # have to be converted before any arithmetic is possible.
            row["qty"] = int(row["qty"])
            row["price"] = float(row["price"])
            rows.append(row)

    return rows


def group_by_rate(rows):
    """Add up the taxable value under each GST rate."""
    totals = {}                                 # rate -> taxable value at that rate

    for row in rows:
        rate = RATES[row["category"]]           # look up the rate for this item
        value = row["qty"] * row["price"]       # what this line is worth before tax

        # .get(rate, 0) gives 0 the first time a rate is met, so there is no need
        # to create the entry separately before adding to it.
        totals[rate] = totals.get(rate, 0) + value

    return totals


def write_invoice(rows, totals, filename):
    """Write the finished invoice out as a text file, ready to print."""
    with open(filename, "w") as f:
        f.write("LAMBDALAB TRADERS — TAX INVOICE\n")
        f.write("Date: " + str(date.today()) + "\n")
        f.write("-" * 46 + "\n")

        # The numbers in {:<16} and {:>10} are column widths. < means align to
        # the left, > to the right, which is what makes the columns line up.
        f.write("{:<16}{:>4}{:>10}{:>12}\n".format("ITEM", "QTY", "RATE", "AMOUNT"))

        # One line per sale.
        for row in rows:
            amount = row["qty"] * row["price"]
            f.write("{:<16}{:>4}{:>10.2f}{:>12.2f}\n".format(
                row["item"], row["qty"], row["price"], amount))

        f.write("-" * 46 + "\n")

        taxable = sum(totals.values())          # the value of everything sold
        tax_total = 0                           # running total of the tax itself

        # One block per rate, in increasing order of rate, which is the order the
        # GST return expects them in.
        for rate in sorted(totals):
            tax = totals[rate] * rate / 100
            tax_total = tax_total + tax
            f.write("Taxable @ {:>2}%{:>19.2f}   GST {:>8.2f}\n".format(
                rate, totals[rate], tax))

        f.write("-" * 46 + "\n")
        f.write("{:<30}{:>16.2f}\n".format("Taxable value", taxable))
        f.write("{:<30}{:>16.2f}\n".format("Total GST", tax_total))
        f.write("{:<30}{:>16.2f}\n".format("GRAND TOTAL", taxable + tax_total))
        f.write("-" * 46 + "\n")
        f.write("Prepared with LambdaLab Billing\n")


# --- the program itself ----------------------------------------------------
# Read, group, write. Each step is a function above, so any one of them can be
# tested on its own.

sales = read_sales("sales.csv")
rate_totals = group_by_rate(sales)
write_invoice(sales, rate_totals, "invoice.txt")

print("Invoice written to invoice.txt")
print(open("invoice.txt").read())      # show it on screen as well, to check it
sales.csv
item,category,qty,price
Rice 5kg,grocery,2,310.00
Notebook,stationery,10,45.00
Pen box,stationery,3,120.00
Table fan,electronics,1,1450.00
⬇️ Take it with you

The full report as a PDF — cover page, certificate, index, code, output, future scope and references, ready to print and fill in. Or the code on its own as a zip.

or one file:

8Sample output

This is a real run, not a mock-up — the transcript below is what the program actually printed.

Command Prompt
C:\LambdaLab\Projects\GST-Invoice> python gst_invoice.py
Invoice written to invoice.txt
LAMBDALAB TRADERS — TAX INVOICE
Date: 2026-08-26
----------------------------------------------
ITEM             QTY      RATE      AMOUNT
Rice 5kg           2    310.00      620.00
Notebook          10     45.00      450.00
Pen box            3    120.00      360.00
Table fan          1   1450.00     1450.00
----------------------------------------------
Taxable @  5%             620.00   GST    31.00
Taxable @ 12%             810.00   GST    97.20
Taxable @ 18%            1450.00   GST   261.00
----------------------------------------------
Taxable value                          2880.00
Total GST                               389.20
GRAND TOTAL                            3269.20
----------------------------------------------
Prepared with LambdaLab Billing

Running it also wrote invoice.txt. This is what that file held afterwards:

invoice.txt
LAMBDALAB TRADERS — TAX INVOICE
Date: 2026-08-26
----------------------------------------------
ITEM             QTY      RATE      AMOUNT
Rice 5kg           2    310.00      620.00
Notebook          10     45.00      450.00
Pen box            3    120.00      360.00
Table fan          1   1450.00     1450.00
----------------------------------------------
Taxable @  5%             620.00   GST    31.00
Taxable @ 12%             810.00   GST    97.20
Taxable @ 18%            1450.00   GST   261.00
----------------------------------------------
Taxable value                          2880.00
Total GST                               389.20
GRAND TOTAL                            3269.20
----------------------------------------------
Prepared with LambdaLab Billing

9Testing

Every case below was actually run and the result recorded as it appeared — including the ones expected to fail.

Test caseExpectedActual
Normal run with four salesGrand total of the four itemsGRAND TOTAL 3269.20
Sales file with a header but no rowsAn invoice totalling zeroGRAND TOTAL 0.00
A single sale10.00 taxable at 12%, total 11.20GRAND TOTAL 11.20
Category not in the rate tableKeyError naming the unknown categoryKeyError: 'toiletries'
sales.csv missing altogetherFileNotFoundErrorFileNotFoundError: [Errno 2] No such file or directory: 'sales.csv'

Two kinds of case are in there on purpose. The boundary cases test the edge of a rule, where a program is most often wrong by one. The failure cases check that it refuses cleanly and says why, instead of quietly producing a wrong answer.

10Advantages

Set against the ways the job is done today:

  • The month-end sorting by tax rate stops being manual work
  • Every invoice is arithmetically correct, every time
  • The rate table is in one place, so a change in the law is one edit
  • The shop keeps its data in a spreadsheet it already understands
  • A printed invoice can be handed over or filed without being rewritten

11Future scope

What this version does not do

A report should be honest about its own limits, and each of these is the reason for one of the additions below:

  • One shop and one day at a time; there is no month view yet
  • The category of an item must be typed correctly, as there is no master item list
  • Returns and credit notes, which carry negative values, are not handled
  • The invoice is plain text, so it prints without a logo or a rupee symbol

Proposed enhancements

This is also where you make the project yours. Pick one or two of these, or something nobody here thought of:

  • Read the shop's existing spreadsheet directly instead of a CSV export
  • Print each invoice to a PDF so it can be emailed to the customer
  • Keep a running month total, so the return is ready on the 1st
  • Add a customer table and print the buyer's GSTIN on the invoice
  • Handle returns and credit notes, which carry negative values

12What you may have to teach yourself

CBSE expects some self-learning in a project, and says so. For this one, that means:

  • How your local shop's GST categories actually map to rates — ask them
  • str.format() width and alignment, which is what makes the columns line up
  • Optional: reportlab or fpdf, if you want real PDF invoices

13Conclusion

The software does what it set out to do. A day's transactions, typed into a file the shopkeeper already knows how to edit, come back as a tax invoice grouped exactly the way the return requires, with the arithmetic done identically every time.

Writing it made clear how much of the original work was not really about tax at all, but about sorting. Once the sorting was given to the computer, what remained was three multiplications and a total.

14References

Every report needs a bibliography. This one used:

  • Computer Science with Python, Class XII — the NCERT / CBSE prescribed textbook, for the chapters on file handling and working with text and CSV files
  • Computer Science with Python, Class XI — for functions, lists, dictionaries and string handling
  • Python 3 documentation — https://docs.python.org/3/
  • CBSE Senior School Curriculum, Computer Science (Subject Code 083) — the project guidelines this report follows
  • LambdaLab — https://www.lambdalab.in
Key Takeaway
The PDF above is the whole report. Cover page, certificate, acknowledgement, index, everything on this page, and the references — in the order CBSE marks them, ready to print. The cover page, certificate and acknowledgement arrive with blank rules where names go, because a certificate with somebody else's name printed on it is not a template. Fill those in, get the certificate signed, and replace the problem with one you have looked into yourself.