
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
149 lines
5.3 KiB
Python
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")
|