DEV Community

lenevo02487
lenevo02487

Posted on

GST Invoice Math in Pure Python — CGST, SGST, IGST Explained with Code

If you've ever built billing software for India, you've hit the question: when does GST split into CGST + SGST, and when is it a single IGST? Get it wrong and the invoice is wrong — even if the total looks right.

I built a small GST invoice generator in pure Python (standard library only) to get this math exactly right. Here's the logic, with a real worked example whose grand total is ₹15,522.

The one rule that decides everything

Compare two state codes:

  • Seller's state code == place-of-supply state code → intra-state → tax splits in half: CGST + SGST
  • They differ → inter-state → one single tax: IGST

That's it. The customer's address doesn't decide it — the place of supply does (for goods, usually where they're delivered). In code:

intra = shop_state_code == place_of_supply_state_code
Enter fullscreen mode Exit fullscreen mode

Per-line math

For each item: taxable = qty × rate, then tax = taxable × GST%. The split is where people slip:

from decimal import Decimal, ROUND_HALF_UP

D = Decimal
CENT = D("0.01")

def money(x):
    """Round to 2 decimals, half-up (the way shops actually bill)."""
    return D(x).quantize(CENT, rounding=ROUND_HALF_UP)

taxable = money(qty * rate)
tax = money(taxable * gst_percent / 100)

if intra:
    cgst = money(tax / 2)
    sgst = tax - cgst          # <-- the important line
    igst = D("0")
else:
    cgst = sgst = D("0")
    igst = tax
Enter fullscreen mode Exit fullscreen mode

Two things to notice:

1. Never use floats for money. 0.1 + 0.2 != 0.3 in floating point, and those errors will surface on an invoice. Decimal with explicit half-up rounding is how real billing works.

2. The odd-paisa trick. Splitting ₹111.75 in half gives ₹55.875 — not a real amount. Round one half up (CGST ₹55.88) and set the other half to tax − cgst (SGST ₹55.87), so the two halves always add back to the exact tax. If you round both halves independently, invoices drift by a paisa and accountants come looking for you.

The worked example (real output)

An intra-state invoice — seller and place of supply in the same state — with five items at three different GST rates:

Item Qty Rate GST Taxable Tax
CTC Tea (1 kg) 10 ₹420 5% ₹4,200.00 ₹210.00
Earthen Cups (pack of 12) 20 ₹60 12% ₹1,200.00 ₹144.00
Chai Masala Combo Pack 15 ₹149 5% ₹2,235.00 ₹111.75
Electric Kettle 1.8L 3 ₹1,299 18% ₹3,897.00 ₹701.46
LED Bulb 9W (set of 4) 8 ₹299 18% ₹2,392.00 ₹430.56

Because it's intra-state, every tax above splits into CGST + SGST halves — including the chai masala's ₹111.75, which becomes CGST ₹55.88 + SGST ₹55.87 (spot the odd-paisa trick doing its job).

Tax summary by rate (this grouping is what goes on the invoice and into GST returns):

GST rate Taxable value CGST SGST Total tax
5% (2.5% + 2.5%) ₹6,435.00 ₹160.88 ₹160.87 ₹321.75
12% (6% + 6%) ₹1,200.00 ₹72.00 ₹72.00 ₹144.00
18% (9% + 9%) ₹6,289.00 ₹566.01 ₹566.01 ₹1,132.02

Totals:

Subtotal (taxable value)   ₹13,924.00
Total GST                  ₹ 1,597.77
Grand total                ₹15,521.77  →  rounded ₹15,522 (round-off +₹0.23)
Enter fullscreen mode Exit fullscreen mode

If the same five items were supplied to a customer in a different state, nothing about the taxable values changes — the same ₹1,597.77 simply appears as IGST instead of the CGST/SGST split, and the total stays ₹15,522. Same money, different tax heads — which is exactly why getting the split right matters for filing, not for the customer.

One more detail: the round-off

Invoices are paid in whole rupees, so the generator rounds the grand total (₹15,521.77 → ₹15,522) and shows the +₹0.23 round-off as its own line. Hiding the difference inside an item rate is how totals stop reconciling — display it openly instead.

Full code

The complete generator — JSON or CSV in, print-ready HTML invoice out, with a per-rate tax summary and the amount in words (Indian numbering: lakh/crore) — is on GitHub: gst-invoice-generator. Run it with the bundled sample and you'll get exactly the ₹15,522 invoice above.


Demo first — on YOUR sample — before you pay anything. Need invoice automation, spreadsheet cleanup, or a scraping/automation tool for your business? Send me a sample of your data and I'll show you a working demo first.

👉 My Python web scraping & automation gig on Fiverr

— Abhishek, Python Automation Developer

Top comments (0)