Billing App: An Open-Source Python Billing & Inventory Platform with Licensing
What it is
Billing App (github.com/Shivay00001/billing_app) is a full-featured desktop billing and inventory platform written in Python. It targets the segment that SaaS billing tools price out: small retail shops, clinics, and service businesses that need GST-ready invoicing, inventory tracking, and PDF exports on a single machine — with no subscription and no internet dependency.
The app runs as a native desktop window (tkinter + ttkbootstrap, "cosmo" theme) with a tabbed interface: Billing, Products, and Dashboard. Under the hood it's a three-layer design — SQLite persistence, dataclass-based domain models, and a ttkbootstrap UI — plus two things most toy billing apps skip entirely: a PDF invoice generator and an offline HMAC-based licensing system with TRIAL/PRO plans.
The problem it solves
Subscription billing software bills you every month for the privilege of printing an invoice. For a single-counter shop in India, the math is hostile: recurring SaaS fees, internet-dependent apps, and UIs that were never designed for GST fields (GSTIN, HSN/SAC codes, state codes, per-item GST rates). Billing App is the opposite bet — one machine, one local SQLite database, and a data model built around Indian tax fields from the start.
How it works: architecture
The repository (~450 KB, 40+ files) is organized cleanly enough to read in an afternoon:
billing_app/
├── app.py # entry point: BillingApp(ttk.Window)
├── database/ # db_init.py, models.py, auto_backup.py
├── license/ # license_manager.py, machine_id.py
├── ui/ # billing, customers, dashboard, invoices,
│ # products, reports, settings screens
├── core/ # app, navigation, payments_config, theme
├── utils/ # pdf_generator, printer, validators
├── billing.py / exporter.py / printer.py / reports.py
├── admin_keygen.py # offline license-key generator
├── build_exe.py # PyInstaller packaging
├── Dockerfile / docker-compose.yml / run.bat / setup_icon.py
└── tests/test_license_smoke.py
Entry point and UI shell
app.py is the entry point. BillingApp subclasses ttk.Window with the cosmo theme, opens at 1100×700, initializes the database, applies the app icon from assets/icon.ico, and builds a ttk.Notebook with tabs. The Billing tab is a two-pane layout — product search and list on the left, cart and payment on the right — wired through perform_search. The Dashboard tab delegates to DashboardFrame, and check_reminders() runs at startup (low-stock alerts and similar operational nudges).
The UI layer (ui/) is the biggest part of the codebase and each screen is a separate module: ui/billing.py (~25 KB) is the point-of-sale screen, ui/invoices.py handles saved invoices, ui/customers.py customer management, ui/products.py inventory, ui/reports.py and ui/dashboard.py analytics views, and ui/settings.py (~16 KB) is the configuration surface. core/theme.py (~24 KB) and core/navigation.py (~13 KB) keep styling and routing out of the screens, which is why the screens read as plain business logic.
Data model: GST-ready from the start
database/models.py uses Python dataclasses as a thin ORM over SQLite, with from_row/to_dict round-tripping. Two entities tell you everything about the target market:
@dataclass
class Product:
name: str = ''
hsn_sac: str = '' # HSN/SAC tax classification code
unit: str = 'NOS'
rate: float = 0.0
gst_rate: float = 18.0 # per-item GST rate
...
@dataclass
class Customer:
name: str = ''
gstin: str = '' # customer's GSTIN
state_code: str = '' # for inter/intra-state tax split
...
db_init.py (~14 KB) creates the schema and database/auto_backup.py handles periodic backups of the SQLite file — the boring feature that saves a shop owner when the machine dies.
Exports, PDFs, and printing
exporter.py writes CSV snapshots — the repo even ships a sample export (exports/2026_01/) with sales.csv, sale_items.csv, products_snapshot.csv, and summary.csv, so you can see the exact output shape without running anything. utils/pdf_generator.py (~10.6 KB) renders invoice PDFs, and utils/printer.py plus top-level printer.py cover receipt printing. Charts on the dashboard come from matplotlib (one of only two runtime deps alongside ttkbootstrap).
Offline licensing, done properly
This is the part I didn't expect. license/license_manager.py (~14.6 KB) implements real offline licensing:
- Keys are signed with an HMAC secret (
admin_keygen.pyis the issuing tool the vendor runs). - Each key is bound to a machine ID (
machine_id.py), so keys can't be shared across machines. - Expiry is validated with anti-tamper checks (the manager guards against clock rollback).
- Two plans: TRIAL (10 invoices, no PDF/dashboard/charts/backup/reports) and PRO (unlimited, everything enabled).
- A revocation hook exists:
REVOCATION_URLfetches a JSON list of revoked license IDs.
Honest caveat: REVOCATION_URL currently points at https://example.com/revoked_licenses.json — a placeholder you must replace with a real endpoint before selling licenses. The HMAC secret lives in both files as b"SECRET_KEY_987654321"; rotate it per deployment. tests/test_license_smoke.py covers key validation.
How to run it
git clone https://github.com/Shivay00001/billing_app.git
cd billing_app
pip install ttkbootstrap pillow
python app.py
Requirements: Python 3.10+ with tkinter (standard on most Linux/macOS installs; Windows Python from python.org includes it). The README notes boot was verified on Python 3.12 under xvfb. For distribution there's build_exe.py (PyInstaller one-folder/one-file build) and a Dockerfile with docker-compose for containerized deployment. verify_setup.py does a pre-flight environment check.
The UI layer in detail
The ui/ directory is where the bulk of the code lives, and it's organized one-screen-per-module, which makes it easy to navigate:
ui/billing.py(~25 KB) — the point-of-sale screen. Product search box wired to<Return>and a Search button, product list on the left, cart with quantities on the right, and a pay flow. This is the screen a shopkeeper lives in all day, and it's the largest module for that reason.ui/products.py(~9.9 KB) — inventory management: add/edit products with HSN/SAC codes, rates, GST rates, and units.ui/customers.py(~9.7 KB) — customer records with GSTIN and full address fields (state codes included, for the inter/intra-state GST split).ui/invoices.py(~8.7 KB) — saved invoice browsing and reprinting.ui/dashboard.py(~4 KB) — KPI overview backed by matplotlib charts.ui/reports.py(~10.5 KB) — sales reports with date filtering.ui/settings.py(~16.3 KB) — the configuration surface: business details for invoice headers, tax defaults, printer settings, backup preferences.
core/theme.py (~24 KB) centralizes the ttkbootstrap styling and core/navigation.py (~12.8 KB) handles screen routing, so individual screens read as business logic rather than widget spaghetti. core/payments_config.py (~3.4 KB) exists as a reserved module for payment integrations — currently a placeholder, but the seam is in the right place.
Database schema and backup
database/db_init.py (~13.8 KB) owns schema creation — tables for products, customers, sales, and sale line items — and database/auto_backup.py (~2.8 KB) snapshots the SQLite file on a schedule. For a single-machine deployment, this is the disaster-recovery story: the entire business state is one file, and it's copied automatically. database.py (top level) provides the lower-level init used by app.py's startup path.
Deployment: desktop, Docker, and exe
Three distribution paths ship with the repo:
- Direct:
pip install ttkbootstrap pillow && python app.py— the dev/test path, plusverify_setup.pyfor pre-flight checks. - Windows exe:
build_exe.pydrives PyInstaller, withsetup_icon.pyand theassets/icon files (icon.ico,icon.png) for a branded installer experience, andrun.batas the launcher. - Container:
Dockerfile+docker-compose.ymlfor a containerized deployment (with a display forwarded, since this is a GUI app).
The licensing smoke test (tests/test_license_smoke.py, ~1.4 KB) exercises key validation end to end, and admin_keygen.py (~1.6 KB) is the offline key-issuing tool — the vendor runs it, the customer pastes a key, machine_id.py binds it to the hardware.
A look at the actual export format
The repo ships a real sample export under exports/2026_01/, so you can evaluate the data model without running the app:
# sales.csv — one row per sale
# sale_items.csv — line items per sale
# products_snapshot.csv — product catalog at export time
# summary.csv — aggregate totals
exporter.py (~3.7 KB) generates these from live data. Combined with utils/pdf_generator.py (~10.6 KB) for customer-facing invoices and utils/validators.py for input validation, the output story is complete: machine-readable exports for the accountant, printable PDFs for the customer.
Code worth borrowing
Even if you never ship a billing app, three modules are worth reading as reference implementations: license/license_manager.py for offline HMAC licensing with machine binding and plan gating (a pattern every indie desktop developer needs once); database/models.py for the dataclass-over-SQLite idiom with from_row/to_dict round-tripping; and main.py-style defensive bootstrapping is absent here — but verify_setup.py plus tests/test_license_smoke.py show the project's testing posture. The codebase is plain, readable, dependency-light Python: the kind you can hand to a junior developer and have them productive in a day.
Honest status
Status: working desktop application. The boot path is verified, the data model is real and GST-aware, exports/PDF/printing are implemented, and the licensing system is genuine HMAC offline licensing — not a hardcoded demo key. What it is not: a cloud product. There's no multi-user sync, no mobile app, no payment-gateway integration, and the revocation endpoint is a stub waiting for a server. If you want to monetize it, the license manager gives you the hard part (offline enforcement); you still need to stand up the revocation endpoint and a checkout flow.
Roadmap-shaped gaps: replace the revocation placeholder with a real hosted endpoint, add UPI/payment-gateway hooks in core/payments_config.py (the module exists and is clearly reserved for this), add barcode-scanner input handling on the billing screen, and optionally a read-only cloud backup of the SQLite file.
Who should look at this
If you're a developer: the dataclass-over-SQLite pattern, the ttkbootstrap theming approach, and the HMAC licensing module are all clean, borrowable reference implementations. If you run a small business: this is a free, offline, GST-ready billing counter that you can run today — and the licensing system means someone could actually sell and support it sustainably.
Frequently asked questions
How do I run Billing App?
Clone the repo, run pip install ttkbootstrap pillow, then python app.py. You need Python 3.10+ with tkinter; boot was verified on Python 3.12. For distribution there's a PyInstaller build script (build_exe.py) and a Dockerfile.
How does the licensing work?
Keys are issued with admin_keygen.py and signed with HMAC, bound to the machine ID, and validated offline by license_manager.py. The TRIAL plan allows 10 invoices without PDF, dashboard, or reports; PRO is unlimited. Replace the placeholder revocation URL with a real endpoint before selling licenses.
Is it GST-ready?
Yes. The data model carries GSTIN, HSN/SAC codes, state codes, and per-item GST rates (default 18%) as first-class fields, so invoices match Indian tax requirements without workarounds.