117 lines
3.7 KiB
Python
117 lines
3.7 KiB
Python
async def m001_initial(db):
|
|
"""
|
|
Initial migration for Castle accounting extension.
|
|
Creates tables for double-entry bookkeeping system.
|
|
"""
|
|
await db.execute(
|
|
f"""
|
|
CREATE TABLE castle.accounts (
|
|
id TEXT PRIMARY KEY,
|
|
name TEXT NOT NULL,
|
|
account_type TEXT NOT NULL,
|
|
description TEXT,
|
|
user_id TEXT,
|
|
created_at TIMESTAMP NOT NULL DEFAULT {db.timestamp_now}
|
|
);
|
|
"""
|
|
)
|
|
|
|
await db.execute(
|
|
"""
|
|
CREATE INDEX idx_accounts_user_id ON castle.accounts (user_id);
|
|
"""
|
|
)
|
|
|
|
await db.execute(
|
|
"""
|
|
CREATE INDEX idx_accounts_type ON castle.accounts (account_type);
|
|
"""
|
|
)
|
|
|
|
await db.execute(
|
|
f"""
|
|
CREATE TABLE castle.journal_entries (
|
|
id TEXT PRIMARY KEY,
|
|
description TEXT NOT NULL,
|
|
entry_date TIMESTAMP NOT NULL,
|
|
created_by TEXT NOT NULL,
|
|
created_at TIMESTAMP NOT NULL DEFAULT {db.timestamp_now},
|
|
reference TEXT
|
|
);
|
|
"""
|
|
)
|
|
|
|
await db.execute(
|
|
"""
|
|
CREATE INDEX idx_journal_entries_created_by ON castle.journal_entries (created_by);
|
|
"""
|
|
)
|
|
|
|
await db.execute(
|
|
"""
|
|
CREATE INDEX idx_journal_entries_date ON castle.journal_entries (entry_date);
|
|
"""
|
|
)
|
|
|
|
await db.execute(
|
|
f"""
|
|
CREATE TABLE castle.entry_lines (
|
|
id TEXT PRIMARY KEY,
|
|
journal_entry_id TEXT NOT NULL,
|
|
account_id TEXT NOT NULL,
|
|
debit INTEGER NOT NULL DEFAULT 0,
|
|
credit INTEGER NOT NULL DEFAULT 0,
|
|
description TEXT,
|
|
FOREIGN KEY (journal_entry_id) REFERENCES castle.journal_entries (id),
|
|
FOREIGN KEY (account_id) REFERENCES castle.accounts (id)
|
|
);
|
|
"""
|
|
)
|
|
|
|
await db.execute(
|
|
"""
|
|
CREATE INDEX idx_entry_lines_journal_entry ON castle.entry_lines (journal_entry_id);
|
|
"""
|
|
)
|
|
|
|
await db.execute(
|
|
"""
|
|
CREATE INDEX idx_entry_lines_account ON castle.entry_lines (account_id);
|
|
"""
|
|
)
|
|
|
|
# Insert default chart of accounts
|
|
default_accounts = [
|
|
# Assets
|
|
("cash", "Cash", "asset", "Cash on hand"),
|
|
("bank", "Bank Account", "asset", "Bank account"),
|
|
("lightning", "Lightning Balance", "asset", "Lightning Network balance"),
|
|
("accounts_receivable", "Accounts Receivable", "asset", "Money owed to the Castle"),
|
|
|
|
# Liabilities
|
|
("accounts_payable", "Accounts Payable", "liability", "Money owed by the Castle"),
|
|
|
|
# Equity
|
|
("member_equity", "Member Equity", "equity", "Member contributions"),
|
|
("retained_earnings", "Retained Earnings", "equity", "Accumulated profits"),
|
|
|
|
# Revenue
|
|
("accommodation_revenue", "Accommodation Revenue", "revenue", "Revenue from stays"),
|
|
("service_revenue", "Service Revenue", "revenue", "Revenue from services"),
|
|
("other_revenue", "Other Revenue", "revenue", "Other revenue"),
|
|
|
|
# Expenses
|
|
("utilities", "Utilities", "expense", "Electricity, water, internet"),
|
|
("food", "Food & Supplies", "expense", "Food and supplies"),
|
|
("maintenance", "Maintenance", "expense", "Repairs and maintenance"),
|
|
("other_expense", "Other Expenses", "expense", "Miscellaneous expenses"),
|
|
]
|
|
|
|
for acc_id, name, acc_type, desc in default_accounts:
|
|
await db.execute(
|
|
"""
|
|
INSERT INTO castle.accounts (id, name, account_type, description)
|
|
VALUES (:id, :name, :type, :description)
|
|
""",
|
|
{"id": acc_id, "name": name, "type": acc_type, "description": desc}
|
|
)
|