A Python-based invoice management application that allows you to create invoices, calculate totals, store invoice data in SQLite, and generate professional PDF invoices.
The project is designed as a practical Python application with separate modules for invoice calculations, database management, PDF generation, and the command-line interface.
- Create new invoices
- Add multiple products or services to an invoice
- Calculate item totals automatically
- Calculate invoice subtotal
- Calculate tax
- Apply discounts
- Calculate the final invoice total
- Generate unique invoice numbers
- Save invoices to a SQLite database
- Store invoice items separately from invoice information
- View previously saved invoices
- List invoice history
- Delete invoices
- Generate PDF invoices
- Automatically create required directories
- Input validation for numbers and required fields
- Command-line interface
invoice-generator/
│
├── main.py
├── invoice.py
├── models.py
├── database.py
├── pdf_generator.py
│
├── data/
│ └── invoices.db
│
└── invoices/
├── INV-0001.pdf
├── INV-0002.pdf
└── ...
The main entry point of the application.
It handles:
- Application startup
- Database initialization
- User input
- Main menu
- Creating invoices
- Listing invoices
- Viewing invoices
- Deleting invoices
Contains the invoice calculation logic.
It handles:
- Creating invoice data
- Generating invoice numbers
- Calculating item totals
- Calculating subtotal
- Calculating tax
- Calculating discounts
- Calculating the final total
Example:
subtotal = 500
tax = subtotal * (14 / 100)
total = subtotal + tax - discountContains the data models used by the application.
The project uses Python dataclasses to represent:
- Invoice items
- Invoices
Example:
InvoiceItem(
name="Website",
quantity=1,
unit_price=500
)An invoice can contain multiple InvoiceItem objects.
Handles SQLite database operations.
It is responsible for:
- Creating the database
- Creating database tables
- Saving invoices
- Saving invoice items
- Retrieving invoices
- Listing invoices
- Deleting invoices
The database is stored at:
data/invoices.db
Handles PDF generation using ReportLab.
It creates PDF invoices containing:
- Invoice number
- Date
- Customer information
- Invoice items
- Quantities
- Unit prices
- Item totals
- Subtotal
- Tax
- Discount
- Final total
Generated PDFs are stored in:
invoices/
The application follows a simple flow:
┌───────────────┐
│ main.py │
│ User Input │
└───────┬───────┘
│
▼
┌───────────────┐
│ invoice.py │
│ Calculations │
└───────┬───────┘
│
┌──────────┴──────────┐
│ │
▼ ▼
┌─────────────────┐ ┌──────────────────┐
│ database.py │ │ pdf_generator.py │
│ SQLite │ │ PDF │
└────────┬────────┘ └────────┬─────────┘
│ │
▼ ▼
┌─────────────────┐ ┌──────────────────┐
│ data/invoices.db│ │ invoices/*.pdf │
└─────────────────┘ └──────────────────┘
You need:
- Python 3.10 or newer
- pip
- ReportLab
SQLite is included with Python, so no separate SQLite installation is required.
git clone https://github.com/yourusername/invoice-generator.gitMove into the project:
cd invoice-generatorLinux/macOS:
python3 -m venv venvWindows:
python -m venv venvsource venv/bin/activatevenv\Scripts\activatepip install reportlabRun:
python main.pyOn Linux systems where python points to Python 2 or is unavailable:
python3 main.pyYou should see:
============================================================
INVOICE GENERATOR
============================================================
1. Create new invoice
2. List invoices
3. View invoice
4. Delete invoice
5. Exit
Choose an option:
Select:
1. Create new invoice
The application asks for customer information:
Customer name: John Smith
Customer email: john@example.com
Then you can add products or services:
--- Invoice Items ---
Add Item
Item/service name: Website Development
Quantity: 1
Unit price: 500
Add another item? (y/n): y
Add Item
Item/service name: Hosting
Quantity: 1
Unit price: 50
Add another item? (y/n): n
Then enter the tax and discount:
Tax (%): 14
Discount: 20
The application calculates the invoice automatically.
Suppose an invoice contains:
Website Development
Quantity: 1
Unit Price: $500
Hosting
Quantity: 1
Unit Price: $50
The item totals are:
Website Development = 1 × $500 = $500
Hosting = 1 × $50 = $50
The subtotal becomes:
Subtotal = $500 + $50
Subtotal = $550
If the tax rate is 14%:
Tax = $550 × 14 / 100
Tax = $77
If the discount is $20:
Total = Subtotal + Tax - Discount
Total = $550 + $77 - $20
Total = $607
The invoice will therefore contain:
Subtotal: $550.00
Tax: $77.00
Discount: $20.00
-----------------------
TOTAL: $607.00
The project uses SQLite.
The database file is:
data/invoices.db
SQLite is useful for this project because it is:
- Lightweight
- Built into Python
- Serverless
- Easy to deploy
- Stored as a single file
- Suitable for a small local application
The application uses two main tables.
Stores general invoice information.
invoices
│
├── id
├── invoice_number
├── date
├── customer_name
├── customer_email
├── tax_rate
├── discount
├── subtotal
├── tax
└── total
Stores the individual items belonging to an invoice.
invoice_items
│
├── id
├── invoice_id
├── name
├── quantity
├── unit_price
└── total
The relationship looks like:
invoices
│
│ 1
│
│
│ many
▼
invoice_items
One invoice can contain many invoice items.
For example:
Invoice INV-0001
│
├── Website
├── Hosting
├── Domain
└── Maintenance
PDF files are generated using the reportlab package.
Generated invoices are saved inside:
invoices/
Example:
invoices/
├── INV-0001.pdf
├── INV-0002.pdf
└── INV-0003.pdf
A generated PDF contains information such as:
INVOICE
Invoice Number: INV-0001
Date: 2026-09-27
Customer:
John Smith
john@example.com
-----------------------------------------------
Item / Service Quantity Price Total
-----------------------------------------------
Website 1 $500 $500
Hosting 1 $50 $50
-----------------------------------------------
Subtotal: $550
Tax (14%): $77
Discount: $20
-----------------------------------------------
TOTAL: $607
The application provides several operations.
Creates a new invoice and:
- Calculates the totals
- Saves the invoice to SQLite
- Saves its items
- Generates a PDF
Displays previously created invoices.
Example:
Invoice Date Customer Total
-----------------------------------------------------------------
INV-0003 2026-09-27 Sarah $450.00
INV-0002 2026-09-26 Ahmed $720.00
INV-0001 2026-09-25 John $607.00
Enter an invoice number:
Invoice number: INV-0001
The application retrieves the invoice and its items from SQLite and displays the complete invoice.
Enter an invoice number:
Invoice number: INV-0001
The application shows the invoice information and asks for confirmation:
Are you sure you want to delete it? (y/n):
Enter:
y
to delete the invoice.
The application validates user input where appropriate.
For example, entering:
Quantity: abc
produces:
Invalid number. Please try again.
Required text fields cannot be left empty.
For example:
Customer name:
produces:
This field cannot be empty.
Negative values are also rejected for values such as:
- Quantity
- Unit price
- Tax
- Discount
This project demonstrates several important Python concepts.
The application is divided into functions:
def create_new_invoice():
...def list_invoices():
...def view_invoice():
...Invoice information can be represented using dictionaries:
invoice = {
"invoice_number": "INV-0001",
"customer_name": "John",
"customer_email": "john@example.com",
"subtotal": 500,
"tax": 70,
"total": 570
}The project also provides structured models through models.py:
@dataclass
class InvoiceItem:
name: str
quantity: float
unit_price: floatThe project uses Python's built-in:
sqlite3module to communicate with the database.
Parameterized queries are used when inserting user data:
cursor.execute(
"""
INSERT INTO invoices (...)
VALUES (?, ?, ?, ...)
""",
values
)This avoids constructing SQL queries by directly concatenating user input.
The project uses:
pathlib.Pathto manage directories and files.
Example:
BASE_DIR = Path(__file__).resolve().parentThe application uses:
try:
...
except Exception:
...to handle errors without unexpectedly terminating the application.
The project currently uses:
reportlab
Install it with:
pip install reportlabPython's standard library provides the other functionality used by the project, including:
sqlite3
datetime
pathlib
dataclasses
typing
A complete invoice creation workflow looks like this:
1. Start application
│
▼
2. Initialize SQLite database
│
▼
3. Select "Create new invoice"
│
▼
4. Enter customer information
│
▼
5. Add invoice items
│
▼
6. Enter tax and discount
│
▼
7. Calculate invoice
│
├───────────────┐
▼ ▼
8. Save database 9. Generate PDF
│ │
▼ ▼
invoices.db INV-0001.pdf
============================================================
INVOICE GENERATOR
============================================================
1. Create new invoice
2. List invoices
3. View invoice
4. Delete invoice
5. Exit
Choose an option: 1
============================================================
CREATE NEW INVOICE
============================================================
--- Customer Information ---
Customer name: John Smith
Customer email: john@example.com
--- Invoice Items ---
Add Item
Item/service name: Website Development
Quantity: 1
Unit price: 500
Add another item? (y/n): y
Add Item
Item/service name: Hosting
Quantity: 1
Unit price: 50
Add another item? (y/n): n
--- Tax & Discount ---
Tax (%): 14
Discount: 20
============================================================
INVOICE
============================================================
Invoice number: INV-0001
Date: 2026-09-27
Customer: John Smith
Email: john@example.com
------------------------------------------------------------
ITEMS
------------------------------------------------------------
Website Development 1.00 x $ 500.00 = $ 500.00
Hosting 1.00 x $ 50.00 = $ 50.00
------------------------------------------------------------
Subtotal: $ 550.00
Tax (14%): $ 77.00
Discount: -$ 20.00
------------------------------------------------------------
TOTAL: $ 607.00
============================================================
Invoice created successfully!
Invoice number: INV-0001
PDF: invoices/INV-0001.pdf
Possible future versions of the project can add:
- Sequential invoice numbering
- Invoice editing
- Duplicate invoice
- Invoice search
- Invoice filtering
- Invoice status
- Due dates
- Payment status
- Notes
- Terms and conditions
- Customer database
- Customer history
- Customer search
- Customer addresses
- Customer phone numbers
- Customer company names
- Company name
- Company logo
- Company address
- Phone number
- Website
- Tax registration number
Support for multiple currencies:
USD
EUR
GBP
EGP
SAR
AED
- Company logo
- Custom colors
- Better typography
- Professional invoice templates
- Page numbers
- Payment instructions
- QR codes
- Bank information
- Signature area
- Graphical user interface
- Web interface
- REST API
- User authentication
- Multiple businesses
- Cloud database
- Online invoice sharing
- Email invoices to customers
A larger version of the application could eventually look like:
invoice-generator/
│
├── app/
│ │
│ ├── models/
│ │ ├── invoice.py
│ │ ├── customer.py
│ │ └── item.py
│ │
│ ├── services/
│ │ ├── invoice_service.py
│ │ ├── pdf_service.py
│ │ └── customer_service.py
│ │
│ ├── database/
│ │ ├── connection.py
│ │ └── repositories.py
│ │
│ └── utils/
│ ├── validators.py
│ └── formatters.py
│
├── data/
│ └── invoices.db
│
├── invoices/
│
├── tests/
│
├── main.py
├── requirements.txt
└── README.md
This structure would make it easier to expand the project into a larger application.
Run the application:
python main.pyTest the following:
1. Create new invoice
Create an invoice containing multiple items.
2. List invoices
Verify that the newly created invoice appears.
3. View invoice
Enter its invoice number and verify that all information is displayed correctly.
4. Delete invoice
Delete a test invoice and verify that it no longer appears in the invoice list.
Check:
invoices/
and verify that the corresponding PDF was generated.
Common issues include:
Error:
ModuleNotFoundError: No module named 'reportlab'
Install it:
pip install reportlabDelete the existing database:
data/invoices.db
Then run the application again.
The application will recreate the database and its tables.
The application stores invoice information locally.
Database:
data/invoices.db
Generated documents:
invoices/
The SQLite database should be backed up if the invoices are important.
The application is currently designed as a local application.
If it is later converted into a web application, additional security should be implemented, including:
- Authentication
- Authorization
- Password hashing
- Input validation
- CSRF protection
- Secure session handling
- Database access controls
- File upload validation
- Secure PDF storage
- HTTPS
This project can be licensed according to the requirements of the project owner.
For an open-source project, a common option is the MIT License.
Deadcode
Dead