Platform

Order and GST tax invoices in Go

A Go package that issues an invoice, with its own gapless number, the moment an order is paid, and keeps a snapshot of the order as it was. A store in India with a valid GSTIN that sells in rupees issues a GST tax invoice instead, and downloads its invoices as files for TallyPrime.

What it does

The module listens for order.paid and issues an invoice for that order: a number from its own yearly sequence, the order’s total and currency, and a snapshot of the whole order as it stood. The admin gets an Invoices screen and a link from each order. The API gets five routes: the list, one invoice, the Tally export, and reading and setting the Tally ledger names.

A store whose profile is in India, whose tax registration is a valid GSTIN and which sells in rupees issues a GST tax invoice instead. It is built once, from what checkout charged, and stored as a document that does not change: supplier and buyer with their GSTINs, each variant’s HSN code, the place of supply from the delivery address, CGST and SGST (UTGST in a union territory without a legislature) within a state and IGST between states and for exports, a summary by rate and the totals. Every other store gets the plain invoice it always did.

On a GST store the Invoices screen also has an Export for Tally card. A period’s tax invoices download as two TallyPrime “Import Data” XML files, ledgers then vouchers. Each invoice becomes one sales voucher, a buyer with a GSTIN becomes a Sundry Debtors ledger named by legal name and GSTIN, and the ledger names are set once to match the accountant’s company.

The package doc explains why it is a module at all: an order is what a shopper asked for, while an invoice is an accounting document with its own gapless sequence and its own retention rules. It needs no third party and talks to nothing outside the store.

Configuration

One setting is required: the seller’s name. All five are Config fields, set in your own main() or through the reference binary’s -invoices flag and its three environment variables. A GST store takes its seller details from the store’s profile under Settings instead, and keeps its Tally ledger names on the Invoices screen.

Invoices module settings — 5 settings, 1 required
SettingEnvironment variableRequiredWhat it does
SellerName INVOICES_SELLER_NAME Yes Heads the plain invoice. Without it the module refuses to register and the store does not start; the reference binary falls back to “This store”. A GST tax invoice names the supplier from the store’s profile instead.
SellerAddress INVOICES_SELLER_ADDRESS No Printed under the seller’s name on the plain invoice. The code’s comment calls it required, but only the name is checked.
TaxID INVOICES_TAX_ID No Printed beside the seller on the plain invoice: a VAT number or whatever applies. A store’s GST mode comes from the tax registration in its profile, not from this field.
NumberFormat — No Builds the number from {year}, {fy} and {seq}; {seq:05} pads to five digits. Defaults to INV-{year}-{seq:05}. On a GST store the count restarts on 1 April, {year} is the year the financial year began and {fy} prints it as 26-27, and a number longer than 16 characters, or with anything other than letters, digits, / and -, is refused: no invoice is issued.
Footer — No Printed at the bottom of every plain invoice.

The module reads its Config struct, not the environment. The variable names are the ones the package’s own example or the reference binary uses; in your own main() you choose where each value comes from. Where a setting has a panel label, the admin’s settings drawer can hold it too, and a value typed there wins over Config.

Setting it up

  1. Choose the number formatThe default is INV-{year}-{seq:05}, which gives INV-2026-00001. Settle yours before the first invoice. A plain store’s count restarts each calendar year, a GST store’s on 1 April; INV/{fy}/{seq:05} is the usual Indian shape.
  2. Install the moduleImport it and pass invoices.New to gocommerce.New with at least SellerName, as below, or run the reference binary with -invoices and the INVOICES_ variables.
  3. For GST, fill in the profileUnder Settings: India, rupees, the GSTIN as the tax registration, the legal name and the address. Give each variant its HS code, which a GST invoice prints as the HSN.
  4. Print, fetch or exportOpen an invoice from its order or the Invoices screen, or GET /api/admin/x/invoices/{orderId}: HTML to print, or JSON with Accept: application/json. A GST store downloads its Tally files from the same screen.

main.go

import (
	"github.com/itswadesh/gocommerce/core"
	"github.com/itswadesh/gocommerce/ext/invoices"
)

app, err := gocommerce.New(cfg,
	invoices.New(invoices.Config{
		SellerName:   "Example Ltd",
		NumberFormat: "INV-{year}-{seq:05}",
	}),
)

The package doc’s own example, with its imports; cfg is your gocommerce.Config. Add SellerAddress, TaxID and Footer the same way. Import path github.com/itswadesh/gocommerce/ext/invoices.

How it works

What it does not do

Read these before an order depends on it. No store is known to run GoCommerce in production yet, so these come from the code, not from anyone’s experience.

FAQ

Questions about the Invoices module

Is it a GST invoice?

Yes, on a store in India with a valid GSTIN that sells in rupees: a tax invoice with both GSTINs, HSN codes, the place of supply and the CGST, SGST or IGST split from what checkout charged, numbered by financial year. It is not an e-invoice: there is no IRN and no e-way bill. Every other store gets a plain invoice that prints the seller’s tax id and no tax line.

Does it connect to Tally?

It exports to it. A GST store downloads a period’s tax invoices as two TallyPrime import files, at most a year at a time, and the accountant imports the ledgers first, then the vouchers. Nothing is sent to Tally by itself, and the files have not yet been test-imported into TallyPrime.

When does a cash-on-delivery order get its invoice?

When it is marked paid, because the module listens for order.paid. A cash-on-delivery order, or a dealer’s order on account, has no invoice until someone records the payment.

Can the numbering have gaps?

Not from this module. The counter is taken under a row lock inside the transaction that writes the invoice, so a failed write gives its number back. A plain store’s count restarts at 1 each calendar year, in UTC; a GST store’s on 1 April, on the store’s clock.

Does the shopper receive the invoice?

Not from this module. It issues the invoice, stores it and serves it to the admin and the API; sending it to the shopper is not in the code.

Source

Everything on this page is read from ext/invoices in the GoCommerce repository, MIT licensed. When this page and the code disagree, the code is right and this page is out of date.TallyPrime is a trademark of its owner; the export writes Tally’s published import format and implies no endorsement. See trademarks.

Try it against a store of your own

The backend + admin quick start runs GoCommerce’s API and admin on your own machine, without a storefront. Add this module to it and try it on test orders before a real one depends on it.

Chat on WhatsApp