The GST Logic Problem
Wageasy is a mobile invoicing app we built for freelancers — focused on the Indian market where GST invoicing is mandatory above a certain turnover threshold. The technical challenge: generating correct, compliant GST invoices on a mobile device and exporting them as PDFs.
India's GST system has two scenarios:
Intra-state: Seller and buyer in the same state results in CGST + SGST (split equally).
Inter-state: Different states results in IGST (full rate).
The rate is always the same (18% for most services) — only how it's split changes. But getting this wrong invalidates the invoice for the client's input tax credit claim.
Our tax calculation is a pure function: it takes the taxable amount, rate, seller state, and buyer state, then determines whether to split into CGST/SGST or apply IGST. The seller's state comes from their profile (set once in settings). The buyer's state comes from the client record.
PDF Generation on Mobile
This is where most React Native invoicing implementations struggle. Options we evaluated:
react-native-html-to-pdf: Renders an HTML string to PDF. Simple but limited styling control and inconsistent across platforms.
expo-print: Expo's built-in print module. Renders HTML to PDF via the platform's native print APIs. We chose this.
Server-side generation: Generate PDFs server-side and download. Adds latency and requires connectivity. We wanted offline support.
We went with expo-print. The approach: an HTML template string with the invoice data interpolated, then rendered to PDF. The share sheet handles delivery — WhatsApp, email, AirDrop, Drive — the user picks.
Key learnings:
- Use @page CSS to control PDF page size and margins
- Inline all styles — no external stylesheets
- Test the output on both iOS and Android — rendering differences exist
Invoice Number Management
GST law requires sequential invoice numbers that reset each financial year (April 1 in India). We store the sequence per financial year, generating numbers like "2025-26/001" that auto-increment and reset when the fiscal year changes.
State Management: Zustand
We used Zustand for global state — invoices, clients, and user profile (including GSTIN and registered state). Simple and effective for this use case. No Redux boilerplate, no Context prop-drilling.
The Tricky Parts
Decimal precision. Financial calculations should never use floating point arithmetic directly. We ran all monetary calculations through a helper that works in paise (the smallest currency unit) to avoid rounding errors.
HSN/SAC code validation. We store a reference table of valid SAC codes for common freelance services. Invalid codes on a GST invoice can trigger compliance notices.
Cross-state detection. India's 29 states and 8 union territories need a complete lookup table. We include both the full name and the GST state code (01 = Jammu & Kashmir, 27 = Maharashtra, etc.).
What's Live
Wageasy is on the App Store and Google Play. It handles GST invoice creation, PDF export, client management, and payment tracking.
Built by [NOTchip](https://notchip.com). If you're building a fintech or invoicing product and need a React Native team with this experience, [reach out](https://notchip.com).