Automated Action bad5cc0eba Build complete SaaS invoicing application with FastAPI
Features:
- JWT authentication with user registration and login
- Customer management with full CRUD operations
- Invoice management with automatic calculations
- Multi-tenant data isolation by user
- SQLite database with Alembic migrations
- RESTful API with comprehensive documentation
- Tax calculations and invoice status tracking
- Code formatted with Ruff linting
2025-06-20 09:52:34 +00:00

149 lines
5.3 KiB
Python

"""Initial tables
Revision ID: 001
Revises:
Create Date: 2024-01-01 00:00:00.000000
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = "001"
down_revision = None
branch_labels = None
depends_on = None
def upgrade() -> None:
# Create users table
op.create_table(
"users",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("email", sa.String(), nullable=False),
sa.Column("hashed_password", sa.String(), nullable=False),
sa.Column("full_name", sa.String(), nullable=False),
sa.Column("company_name", sa.String(), nullable=True),
sa.Column("is_active", sa.Boolean(), nullable=True),
sa.Column(
"created_at",
sa.DateTime(timezone=True),
server_default=sa.text("CURRENT_TIMESTAMP"),
nullable=True,
),
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=True),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(op.f("ix_users_id"), "users", ["id"], unique=False)
op.create_index(op.f("ix_users_email"), "users", ["email"], unique=True)
# Create customers table
op.create_table(
"customers",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("name", sa.String(), nullable=False),
sa.Column("email", sa.String(), nullable=False),
sa.Column("phone", sa.String(), nullable=True),
sa.Column("address", sa.Text(), nullable=True),
sa.Column("city", sa.String(), nullable=True),
sa.Column("state", sa.String(), nullable=True),
sa.Column("zip_code", sa.String(), nullable=True),
sa.Column("country", sa.String(), nullable=True),
sa.Column("user_id", sa.Integer(), nullable=False),
sa.Column(
"created_at",
sa.DateTime(timezone=True),
server_default=sa.text("CURRENT_TIMESTAMP"),
nullable=True,
),
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=True),
sa.ForeignKeyConstraint(
["user_id"],
["users.id"],
),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(op.f("ix_customers_id"), "customers", ["id"], unique=False)
# Create invoices table
op.create_table(
"invoices",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("invoice_number", sa.String(), nullable=False),
sa.Column("customer_id", sa.Integer(), nullable=False),
sa.Column("user_id", sa.Integer(), nullable=False),
sa.Column(
"issue_date",
sa.DateTime(timezone=True),
server_default=sa.text("CURRENT_TIMESTAMP"),
nullable=True,
),
sa.Column("due_date", sa.DateTime(timezone=True), nullable=False),
sa.Column(
"status",
sa.Enum(
"DRAFT", "SENT", "PAID", "OVERDUE", "CANCELLED", name="invoicestatus"
),
nullable=True,
),
sa.Column("subtotal", sa.Numeric(precision=10, scale=2), nullable=True),
sa.Column("tax_rate", sa.Numeric(precision=5, scale=2), nullable=True),
sa.Column("tax_amount", sa.Numeric(precision=10, scale=2), nullable=True),
sa.Column("total", sa.Numeric(precision=10, scale=2), nullable=True),
sa.Column("notes", sa.Text(), nullable=True),
sa.Column(
"created_at",
sa.DateTime(timezone=True),
server_default=sa.text("CURRENT_TIMESTAMP"),
nullable=True,
),
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=True),
sa.ForeignKeyConstraint(
["customer_id"],
["customers.id"],
),
sa.ForeignKeyConstraint(
["user_id"],
["users.id"],
),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("invoice_number"),
)
op.create_index(op.f("ix_invoices_id"), "invoices", ["id"], unique=False)
# Create invoice_items table
op.create_table(
"invoice_items",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("invoice_id", sa.Integer(), nullable=False),
sa.Column("description", sa.String(), nullable=False),
sa.Column("quantity", sa.Numeric(precision=10, scale=2), nullable=False),
sa.Column("unit_price", sa.Numeric(precision=10, scale=2), nullable=False),
sa.Column("total_price", sa.Numeric(precision=10, scale=2), nullable=False),
sa.Column(
"created_at",
sa.DateTime(timezone=True),
server_default=sa.text("CURRENT_TIMESTAMP"),
nullable=True,
),
sa.ForeignKeyConstraint(
["invoice_id"],
["invoices.id"],
),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(op.f("ix_invoice_items_id"), "invoice_items", ["id"], unique=False)
def downgrade() -> None:
op.drop_index(op.f("ix_invoice_items_id"), table_name="invoice_items")
op.drop_table("invoice_items")
op.drop_index(op.f("ix_invoices_id"), table_name="invoices")
op.drop_table("invoices")
op.drop_index(op.f("ix_customers_id"), table_name="customers")
op.drop_table("customers")
op.drop_index(op.f("ix_users_email"), table_name="users")
op.drop_index(op.f("ix_users_id"), table_name="users")
op.drop_table("users")