India compliance — unified view
One-page overview of Indian statutory compliance the ERP touches: monthly GST, TDS, and audit-relevant exports. This is the "what's due when and where does it live in the app" reference — the deep mechanics live on the dedicated GST and TDS pages.
Audience: the CA or internal compliance lead who needs to know what the app emits and what still requires manual effort outside it.
1. Deadlines calendar
All dates refer to the month following the period being reported — e.g. GSTR-1 for April transactions is due 11 May.
| Cadence | Form | Due date | What it covers | App support |
|---|---|---|---|---|
| Monthly | GSTR-1 | 11th of next month | Outward supplies (sales register) | Export via Finance → Reports → GST Summary; payload builder in src/lib/gstReports.ts. |
| Monthly | GSTR-3B | 20th of next month (staggered for certain states) | Summary return + GST payment | Export via Finance → Reports → GST Summary; GSTN portal upload is stub. |
| Monthly | TDS Form 281 (challan) | 7th of next month | TDS deposit to the government | Not automated — see §5 gap list. |
| Quarterly | Form 26Q | End of month following quarter (31 Jul / 31 Oct / 31 Jan / 31 May) | Non-salary TDS return | Export CSV via Finance → TDS → Export 26Q (permission: finance.tds.export). |
| Annual | Income Tax audit (3CA/3CD) | 30 September | Statutory audit package | Exports via Reports + Chart of Accounts + exportFinanceWorkbook.ts. |
| Annual | GSTR-9 / 9C | 31 December | Annual GST return + reconciliation | No direct export; pull from GSTR-3B exports and reconcile externally. |
Portal upload is still manual
The app builds the GSTR-1 / 3B JSON payload, but pushing it to
the GSTN portal is a stub (src/lib/gstnApiClient.ts). Until the
GSTN ASP/GSP integration is enabled, a finance user downloads the
payload and uploads via the GSTN portal UI.
2. Registration artifacts in the app
2.1 GSTIN — party-level
Columns added by
supabase/migrations/20260418150000_gst_primitives.sql:
| Table | Column | Validator | Note |
|---|---|---|---|
Customer |
gstNumber |
isValidGstin() in src/lib/gstin.ts:40 |
Optional; required for B2B invoices to claim input credit. |
Supplier |
gstNumber |
isValidGstin() |
Optional; determines whether we post 1400 GST Input Credit on the supplier invoice. |
Agent |
gstNumber |
isValidGstin() |
Added in an earlier migration. |
Validation is shape-only — the 15-character GSTIN regex. Checksum verification is deferred to the GST portal at upload time.
2.2 PAN — supplier level
Supplier.panNumber column — added by
supabase/migrations/20260418150000_tds_scaffolding.sql:141.
- Required on 26Q (a deductee without a PAN triggers the 20% penal rate per §206AA — the export surfaces this separately).
- Free-text TEXT column; no DB-level format CHECK. UI-side regex validation lives in the supplier form.
2.3 HSN / SAC — line-item level
Columns added to (20260418150000_gst_primitives.sql):
| Table | hsnCode |
sacCode |
|---|---|---|
QuotationLineItem |
✓ | ✓ |
SupplierTransaction |
✓ | ✓ |
Invoice |
✓ | ✓ |
- HSN = Harmonized System of Nomenclature (goods).
- SAC = Services Accounting Code (services).
- No DB CHECK on mutual exclusivity — travel is mostly SAC
(
998555Tour operator services, etc.), but the table holds mixed goods + services historically. GroupInvoice/AgentInvoicestore line items as JSONB. HSN/SAC lives inside the JSON payload.
2.4 Default section + deducteeType — supplier-level TDS
Columns on Supplier (same migration):
tdsSection(text, nullable) — e.g.'194C','194J','194Q'.deducteeType(text, default'company') — one of'individual' | 'huf' | 'company' | 'any'. Constrained bySupplier_deducteeType_check.
These pre-populate the "Deduct TDS" toggle on the supplier payment form so common cases (professional fees @ 10% to a registered consultant) don't require re-entering the section every time.
3. Month-end workflow (finance lead)
gantt
title End-of-month compliance (April → May)
dateFormat YYYY-MM-DD
section GST
Close books for April (period lock) :done, book, 2026-04-30, 1d
Export GSTR-1 JSON :active, gstr1, 2026-05-01, 3d
Reconcile + upload GSTR-1 to portal : gstr1b, after gstr1, 5d
File GSTR-1 (due 11 May) :crit, gstr1c, 2026-05-10, 1d
Export GSTR-3B payload + pay GST : gstr3b, 2026-05-12, 5d
File GSTR-3B (due 20 May) :crit, gstr3bc, 2026-05-19, 1d
section TDS
Generate Form 281 challans : tds281, 2026-05-02, 2d
Deposit TDS (due 7 May) :crit, tds281c, 2026-05-06, 1d
Mark TDSDeduction rows status=deposited : tdsdep, 2026-05-07, 1d
Outline:
- Close April books. Lock
AccountingPeriodfor April — blocks any further postings into the month (overview.md §3). - GSTR-1 (by 11 May). Finance → Reports → GST Summary → select April, export JSON. Upload to GSTN portal. Reconcile any discrepancies and file.
- TDS deposit (by 7 May). Review the TDS Deduction ledger for
April with status
pending. Generate challans (manual). Deposit via Income Tax portal. Mark rowsdepositedand stashchallanNo challanDate.- GSTR-3B (by 20 May). Export the 3B summary from the GST
Summary report. Calculate net tax = output GST (
2400) − input credit (1400). Pay on portal. File. - Quarterly 26Q (at end of July for Q1 Apr–Jun). Export 26Q CSV
(Finance → TDS → Export 26Q, permission
finance.tds.export). File via TRACES / NSDL.
4. Where each artifact is produced
| Artifact | File / helper | Entry point in UI |
|---|---|---|
| GSTIN validator | src/lib/gstin.ts |
Runs client-side on every form that captures a GSTIN. |
| GSTR-1 / GSTR-3B payload builder | src/lib/gstReports.ts |
Finance → Reports → GST Summary → Export. |
| GSTN portal client (stub) | src/lib/gstnApiClient.ts |
Not yet wired to a button. |
| TDS calculator + thresholds | src/lib/tds.ts |
Supplier payment form → "Deduct TDS" panel. |
| TDS rate seed | supabase/migrations/20260418150000_tds_scaffolding.sql:113-134 |
Editable via a TDS rate master UI. |
| 26Q CSV | src/lib/tds.ts (exporter function) |
Finance → TDS → Export 26Q. |
| Statutory reports (TB, P&L, BS) | src/lib/api.ts + RPC migrations (20260415180*_finance_*_rpc.sql) |
Finance → Reports. |
| Workbook export | src/lib/exportFinanceWorkbook.ts |
Finance → Reports → Export Workbook. |
5. Gap list (not yet automated)
Tracked work items the finance team should expect to do manually until these ship:
| Gap | What's missing | Workaround today |
|---|---|---|
| GSTN portal direct upload | gstnApiClient.ts is a stub. |
Download the generated JSON and upload via the portal UI. |
| TDS Form 281 challan generation | No PDF / IT portal integration. | Use the Income Tax portal directly with the figures from the TDS Deduction ledger. |
| TDSDeduction.status = deposited → certificate_issued flow | No PATCH wired from the UI. | Update the row directly in the admin console, or via /admin if a field-editor exists. |
| 26AS reconciliation | No import of the 26AS TDS-from-customers report. | Download 26AS manually; reconcile in Excel against our AgentReceivable / customer invoices. |
| GSTR-9 / 9C annual return | No dedicated export. | Aggregate the monthly GSTR-1 + 3B exports externally. |
| Reverse charge (RCM) | No explicit RCM flag on SupplierTransaction. |
Currently posted as a regular 1400 input credit; RCM detail lives in the memo. |
| E-invoicing (IRN) | No IRN generation for B2B invoices > ₹5 Cr-threshold. | Generate IRN on the portal and stamp it onto the invoice manually. |
| GSTIN checksum validation | isValidGstin() does shape only. |
Portal rejects bad checksums at upload. |
| PAN format validation at DB level | No CHECK constraint on Supplier.panNumber. |
UI regex only. |
| Period-lock audit signal | Attempted posts into a locked period are rejected by the trigger but not logged to AuditLog. |
Check Postgres warning logs if needed. |
6. What auditors will ask for, and where it lives
| Ask | Source |
|---|---|
| Full GL (chart + posted journals, period-bounded) | Finance → Reports → Day Book export + Trial Balance; direct SQL on JournalEntry + JournalLine as a backstop. |
| Approval log for every journal (maker ≠ checker) | AuditLog filtered to finance.voucher.approve; cross-join with JournalEntry.createdBy. See audit-trail.md §6. |
| GST input credit schedule | Ledger of account 1400 GST Input Credit in the period. |
| GST output (payable) schedule | Ledger of account 2400 GST Payable in the period. |
| TDS deduction register | TDSDeduction table for the period, pulled via Finance → TDS → Export. |
| Opening / closing balances | Trial Balance export at period boundary. |
| Fixed-asset register | Ledgers of 1500 / 1510 / 1520 / 1530. Depreciation posting is manual journal via 6600 Depreciation. |
7. Cross-references
- GST (India) — GSTIN, HSN/SAC, GSTR-1 / 3B deep dive.
- TDS (India) — sections, calculator, 26Q CSV.
- Chart of accounts —
1400 GST Input Credit,2400 GST Payable,2401 TDS Payable. - Audit trail — statutory auditor's queries.
- Reports — report catalog including GST Summary.
docs/PERMISSIONS.md§4.4 —finance.tds.*andfinance.reports.gst_summary.*permissions.