Skip to main content

Pricing & GST

The Paise Convention

All prices are stored as integers in paise (₹1 = 100 paise). This avoids float rounding errors — a well-known problem in financial software.

User SaysStored AsDisplay Formula
"₹14"14001400 / 100 = 14.00
"₹99.50"99509950 / 100 = 99.50
"₹250"2500025000 / 100 = 250.00

The system prompt tells the LLM to convert:

Prices are stored in paise (₹1 = 100 paise) — convert user amounts to paise when storing.
Prices quoted by sellers include GST — the stored sell_price is GST-inclusive (MRP).

GST-Inclusive Pricing

In India, retail prices (MRP) include GST. The sell_price field stores the GST-inclusive price. When displaying a bill, the system:

  1. Derives the taxable value from the inclusive price
  2. Splits the tax into CGST (Central) and SGST (State) at half the slab rate each

The split_gst Algorithm

def split_gst(inclusive_paise: int, gst_slab: int) -> tuple[int, int]:
if gst_slab == 0:
return (0, 0)
taxable = round(inclusive_paise * 100 / (100 + gst_slab))
total_tax = inclusive_paise - taxable
cgst = round(total_tax / 2)
sgst = total_tax - cgst
return (cgst, sgst)

Examples

Sell PriceGST SlabTaxableCGSTSGSTTotal TaxGrand Total
₹100 (10000 paise)0%1000000010000
₹100 (10000 paise)5%952423823847610000
₹100 (10000 paise)12%8929536535107110000
₹100 (10000 paise)18%8475762763152510000
₹37 (3700 paise)5%352488881763700

Note: cgst and sgst may differ by 1 paise due to rounding (total tax is always correct).

Per-Item GST Computation

GST is computed per line item, not per bill. Each inventory item has its own gst_slab:

class Inventory(SQLModel, table=True):
gst_slab: int = 0 # 0, 5, 12, 18, 28
sell_price: int # GST-inclusive MRP in paise
hsn_code: str | None # Harmonized System code (8 chars)

For a bill with multiple items at different slabs:

for item in bill_items:
inv = session.get(Inventory, item.inventory_id)
line_total = inv.sell_price * item.quantity
cgst, sgst = split_gst(line_total, inv.gst_slab)
subtotal += line_total - (cgst + sgst)
cgst_total += cgst
sgst_total += sgst
grand_total = subtotal + cgst_total + sgst_total

HSN Code Auto-Lookup

When adding a new product, the discover_product_info tool uses the LLM (via a prompt) to suggest the correct HSN code and GST slab. This is the only place the model's "knowledge" is trusted — for product classification, not pricing.

Invoice Display

The bill display shows the full GST breakup:

Bill #42 — Finalized
Subtotal: ₹952.38
CGST (2.5%): ₹23.81
SGST (2.5%): ₹23.81
─────────────────────
Grand Total: ₹1,000.00
─────────────────────
Payment: UPI (ref: 12345)

This is rendered by billing/formatter.py using the BillDisplay dataclass.

Guardrails

if sell_price < cost_price:
raise ValueError(
f"Sell price (₹{sell_price/100:.2f}) must be >= "
f"cost price (₹{cost_price/100:.2f})"
)

The system prevents below-cost sales. The LLM sees this error and can explain it to the user.