
- Create User model and database schema - Add JWT authentication with secure password hashing - Create authentication endpoints for registration and login - Update invoice routes to require authentication - Ensure users can only access their own invoices - Update documentation in README.md
389 lines
12 KiB
Markdown
389 lines
12 KiB
Markdown
# Invoice Generation Service
|
|
|
|
This is a FastAPI application for generating and managing invoices. It allows users to register, login, and manage their invoices with full authentication and user-specific data access.
|
|
|
|
## Features
|
|
|
|
- User registration and authentication with JWT
|
|
- Generate invoices with automatic invoice number generation
|
|
- Store invoice details in SQLite database
|
|
- Retrieve invoice information by ID or invoice number
|
|
- Update invoice details and status
|
|
- Delete invoices
|
|
- User-specific invoice management (users can only access their own invoices)
|
|
- Advanced search and filtering options
|
|
- Web-based user interface for invoice management
|
|
- Health check endpoint
|
|
|
|
## Technical Stack
|
|
|
|
- **Framework**: FastAPI
|
|
- **Database**: SQLite with SQLAlchemy ORM
|
|
- **Migrations**: Alembic
|
|
- **Validation**: Pydantic
|
|
- **Authentication**: JWT (JSON Web Tokens)
|
|
- **Password Hashing**: Bcrypt
|
|
- **Frontend**: Jinja2 Templates, HTML, CSS, JavaScript
|
|
- **Linting**: Ruff
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
.
|
|
├── alembic.ini # Alembic configuration file
|
|
├── app # Application package
|
|
│ ├── api # API routes
|
|
│ │ └── routes # API route modules
|
|
│ │ ├── __init__.py # Routes initialization
|
|
│ │ ├── invoices.py # Invoice API routes
|
|
│ │ └── frontend.py # Frontend routes
|
|
│ ├── core # Core functionality
|
|
│ │ ├── config.py # Application settings
|
|
│ │ ├── database.py # Database connection setup
|
|
│ │ └── utils.py # Utility functions
|
|
│ ├── models # SQLAlchemy models
|
|
│ │ ├── __init__.py # Models initialization
|
|
│ │ └── invoice.py # Invoice and InvoiceItem models
|
|
│ ├── schemas # Pydantic schemas
|
|
│ │ ├── __init__.py # Schemas initialization
|
|
│ │ └── invoice.py # Invoice-related schemas
|
|
│ ├── static # Static files
|
|
│ │ ├── css # CSS styles
|
|
│ │ │ └── styles.css # Main stylesheet
|
|
│ │ └── js # JavaScript files
|
|
│ │ └── main.js # Main JavaScript file
|
|
│ └── templates # Jinja2 templates
|
|
│ ├── base.html # Base template with layout
|
|
│ ├── home.html # Home page
|
|
│ ├── create_invoice.html # Invoice creation form
|
|
│ ├── search_invoice.html # Search for invoices
|
|
│ └── invoice_details.html # Invoice details page
|
|
├── main.py # Application entry point
|
|
├── migrations # Alembic migrations
|
|
│ ├── env.py # Alembic environment
|
|
│ ├── script.py.mako # Migration script template
|
|
│ └── versions # Migration scripts
|
|
│ └── ef0aaab3a275_initial_database_tables.py # Initial migration
|
|
├── requirements.txt # Project dependencies
|
|
└── pyproject.toml # Ruff configuration
|
|
```
|
|
|
|
## API Endpoints
|
|
|
|
### Health Check
|
|
|
|
- `GET /health`: Check if the service is running
|
|
|
|
### Authentication API
|
|
|
|
- `POST /api/v1/auth/register`: Register a new user
|
|
- Request body: User registration details (email, username, password, etc.)
|
|
- Returns: User details (without password)
|
|
- `POST /api/v1/auth/login`: Login and get an access token
|
|
- Request body: Form data with username/email and password
|
|
- Returns: JWT access token
|
|
- `GET /api/v1/auth/me`: Get current user details
|
|
- Headers: `Authorization: Bearer {token}`
|
|
- Returns: Current user details
|
|
|
|
### Invoice Management API
|
|
|
|
All invoice endpoints require authentication with a valid JWT token in the Authorization header: `Authorization: Bearer {token}`
|
|
|
|
- `POST /api/v1/invoices`: Create a new invoice (associated with the authenticated user)
|
|
- `GET /api/v1/invoices`: List invoices belonging to the authenticated user (with pagination)
|
|
- Query parameters:
|
|
- `skip`: Number of records to skip (default: 0)
|
|
- `limit`: Maximum number of records to return (default: 100)
|
|
- `fields`: Comma-separated list of fields to include in the response (e.g., "id,invoice_number,total_amount")
|
|
- `status`: Filter invoices by status (e.g., "PENDING", "PAID", "CANCELLED")
|
|
- `sort_order`: Sort by creation date, either "asc" (oldest first) or "desc" (newest first, default)
|
|
- Many more filtering options available (see Advanced Filtering section)
|
|
- `GET /api/v1/invoices/{invoice_id}`: Get a specific invoice by ID (must belong to the authenticated user)
|
|
- Query parameters:
|
|
- `fields`: Comma-separated list of fields to include in the response (e.g., "id,invoice_number,total_amount")
|
|
- `GET /api/v1/invoices/find`: Find an invoice by invoice number (must belong to the authenticated user)
|
|
- Query parameters:
|
|
- `invoice_number`: Invoice number to search for (required)
|
|
- `fields`: Comma-separated list of fields to include in the response (e.g., "id,invoice_number,total_amount")
|
|
- `PATCH /api/v1/invoices/{invoice_id}`: Update an invoice (must belong to the authenticated user)
|
|
- `PATCH /api/v1/invoices/{invoice_id}/status`: Update invoice status (must belong to the authenticated user)
|
|
- `DELETE /api/v1/invoices/{invoice_id}`: Delete an invoice (must belong to the authenticated user)
|
|
|
|
### Frontend Routes
|
|
|
|
- `GET /`: Home page with list of recent invoices
|
|
- `GET /create`: Form to create a new invoice
|
|
- `POST /create`: Process invoice creation form
|
|
- `GET /search`: Form to search for invoices by number
|
|
- `POST /search`: Process invoice search
|
|
- `GET /invoice/{invoice_id}`: View invoice details
|
|
- `POST /invoice/{invoice_id}/status`: Update invoice status
|
|
|
|
## Setup and Installation
|
|
|
|
1. Clone the repository
|
|
2. Install dependencies:
|
|
```
|
|
pip install -r requirements.txt
|
|
```
|
|
3. Run migrations:
|
|
```
|
|
alembic upgrade head
|
|
```
|
|
4. Start the application:
|
|
```
|
|
uvicorn main:app --reload
|
|
```
|
|
|
|
## Authentication
|
|
|
|
The application uses JWT (JSON Web Tokens) for authentication. Here's how to use it:
|
|
|
|
### User Registration
|
|
|
|
To create a new user account:
|
|
|
|
```
|
|
POST /api/v1/auth/register
|
|
```
|
|
|
|
Request body:
|
|
```json
|
|
{
|
|
"email": "user@example.com",
|
|
"username": "user123",
|
|
"password": "securepassword",
|
|
"full_name": "John Doe"
|
|
}
|
|
```
|
|
|
|
### User Login
|
|
|
|
To log in and get an access token:
|
|
|
|
```
|
|
POST /api/v1/auth/login
|
|
```
|
|
|
|
This endpoint accepts form data (not JSON) with:
|
|
- `username`: Your username or email
|
|
- `password`: Your password
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
"token_type": "bearer"
|
|
}
|
|
```
|
|
|
|
### Using the Token
|
|
|
|
Include the token in the Authorization header for all invoice-related requests:
|
|
|
|
```
|
|
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
|
```
|
|
|
|
### Getting Current User
|
|
|
|
To get the details of the currently authenticated user:
|
|
|
|
```
|
|
GET /api/v1/auth/me
|
|
```
|
|
|
|
Headers:
|
|
```
|
|
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
|
```
|
|
|
|
## API Documentation
|
|
|
|
Once the application is running, you can access:
|
|
- Interactive API documentation at `/docs` (Swagger UI)
|
|
- Alternative API documentation at `/redoc` (ReDoc)
|
|
|
|
## Web Interface
|
|
|
|
The application comes with a full web interface that allows users to:
|
|
- View a list of recent invoices on the home page
|
|
- Create new invoices using a dynamic form
|
|
- Search for existing invoices by invoice number
|
|
- View detailed invoice information
|
|
- Update invoice status (PENDING, PAID, CANCELLED)
|
|
- Print invoices
|
|
|
|
## Invoice Number Format
|
|
|
|
Invoices are automatically assigned a unique invoice number with the format:
|
|
- `INV-YYYYMM-XXXXXX`, where:
|
|
- `INV` is a fixed prefix
|
|
- `YYYYMM` is the year and month (e.g., 202307 for July 2023)
|
|
- `XXXXXX` is a random alphanumeric string
|
|
|
|
## Query Parameters
|
|
|
|
### Field Filtering
|
|
|
|
The API supports field filtering for GET operations. This allows clients to request only the specific fields they need, which can improve performance and reduce bandwidth usage.
|
|
|
|
#### How to Use Field Filtering:
|
|
|
|
1. Add a `fields` query parameter to GET requests
|
|
2. Specify a comma-separated list of field names to include in the response
|
|
|
|
#### Example:
|
|
|
|
To get only the ID, invoice number, and total amount of invoices:
|
|
```
|
|
GET /api/v1/invoices?fields=id,invoice_number,total_amount
|
|
```
|
|
|
|
This would return:
|
|
```json
|
|
[
|
|
{
|
|
"id": 1,
|
|
"invoice_number": "INV-202307-A1B2C3",
|
|
"total_amount": 100.0
|
|
},
|
|
{
|
|
"id": 2,
|
|
"invoice_number": "INV-202307-D4E5F6",
|
|
"total_amount": 200.0
|
|
}
|
|
]
|
|
```
|
|
|
|
### Status Filtering
|
|
|
|
The API supports filtering invoices by their status (PENDING, PAID, CANCELLED).
|
|
|
|
#### How to Use Status Filtering:
|
|
|
|
1. Add a `status` query parameter to the GET request
|
|
2. Specify one of the allowed status values: "PENDING", "PAID", or "CANCELLED"
|
|
|
|
#### Example:
|
|
|
|
To get only paid invoices:
|
|
```
|
|
GET /api/v1/invoices?status=PAID
|
|
```
|
|
|
|
To combine with other parameters:
|
|
```
|
|
GET /api/v1/invoices?status=PENDING&fields=id,invoice_number,total_amount&limit=5
|
|
```
|
|
|
|
### Advanced Filtering
|
|
|
|
The API supports advanced filtering options for more precise control over your invoice queries.
|
|
|
|
#### Date Range Filtering
|
|
|
|
Filter invoices by creation date or due date:
|
|
|
|
- `created_after`: Filter invoices created on or after this date (YYYY-MM-DD)
|
|
- `created_before`: Filter invoices created on or before this date (YYYY-MM-DD)
|
|
- `due_after`: Filter invoices due on or after this date (YYYY-MM-DD)
|
|
- `due_before`: Filter invoices due on or before this date (YYYY-MM-DD)
|
|
|
|
Examples:
|
|
|
|
```
|
|
# Get invoices created in January 2023
|
|
GET /api/v1/invoices?created_after=2023-01-01&created_before=2023-01-31
|
|
|
|
# Get overdue invoices (due before today)
|
|
GET /api/v1/invoices?due_before=2023-07-01&status=PENDING
|
|
```
|
|
|
|
#### Customer Filtering
|
|
|
|
Search for invoices by customer information:
|
|
|
|
- `customer_name`: Filter invoices by customer name (case-insensitive, partial match)
|
|
- `customer_email`: Filter invoices by customer email (case-insensitive, partial match)
|
|
|
|
Examples:
|
|
|
|
```
|
|
# Find all invoices for customers with "smith" in their name
|
|
GET /api/v1/invoices?customer_name=smith
|
|
|
|
# Find invoices for customers with a specific email domain
|
|
GET /api/v1/invoices?customer_email=example.com
|
|
```
|
|
|
|
#### Amount Range Filtering
|
|
|
|
Filter invoices by total amount:
|
|
|
|
- `min_amount`: Filter invoices with total amount greater than or equal to this value
|
|
- `max_amount`: Filter invoices with total amount less than or equal to this value
|
|
|
|
Examples:
|
|
|
|
```
|
|
# Get invoices with amounts between $100 and $500
|
|
GET /api/v1/invoices?min_amount=100&max_amount=500
|
|
|
|
# Get high-value invoices
|
|
GET /api/v1/invoices?min_amount=1000
|
|
```
|
|
|
|
### Advanced Sorting
|
|
|
|
The API supports sorting invoices by various fields:
|
|
|
|
- `sort_by`: Field to sort by. Available options:
|
|
- `date_created`: Sort by creation date (default)
|
|
- `due_date`: Sort by due date
|
|
- `total_amount`: Sort by invoice amount
|
|
- `customer_name`: Sort alphabetically by customer name
|
|
- `sort_order`: Sort direction:
|
|
- `asc`: Ascending order (oldest/smallest/A-Z first)
|
|
- `desc`: Descending order (newest/largest/Z-A first, this is the default)
|
|
|
|
Examples:
|
|
|
|
```
|
|
# Get highest-value invoices first
|
|
GET /api/v1/invoices?sort_by=total_amount&sort_order=desc
|
|
|
|
# Get invoices sorted alphabetically by customer name
|
|
GET /api/v1/invoices?sort_by=customer_name&sort_order=asc
|
|
|
|
# Get invoices with the earliest due dates first
|
|
GET /api/v1/invoices?sort_by=due_date&sort_order=asc
|
|
```
|
|
|
|
### Combining Filters
|
|
|
|
All filter parameters can be combined for precise results:
|
|
|
|
```
|
|
# Get pending invoices over $500 created in 2023, sorted by amount (highest first)
|
|
GET /api/v1/invoices?status=PENDING&min_amount=500&created_after=2023-01-01&sort_by=total_amount&sort_order=desc
|
|
|
|
# Get paid invoices for a specific customer
|
|
GET /api/v1/invoices?status=PAID&customer_name=acme&sort_by=date_created&sort_order=desc
|
|
```
|
|
|
|
### Available Fields:
|
|
|
|
Invoices have the following fields that can be filtered:
|
|
- `id`
|
|
- `invoice_number`
|
|
- `date_created`
|
|
- `due_date`
|
|
- `total_amount`
|
|
- `status`
|
|
- `customer_name`
|
|
- `customer_email`
|
|
- `customer_address`
|
|
- `notes`
|
|
- `items` (this includes related invoice items) |