async def m001_initial(db): """ Initial migration for Castle accounting extension. Creates tables for double-entry bookkeeping system. """ await db.execute( f""" CREATE TABLE 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 accounts (user_id); """ ) await db.execute( """ CREATE INDEX idx_accounts_type ON accounts (account_type); """ ) await db.execute( f""" CREATE TABLE 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 journal_entries (created_by); """ ) await db.execute( """ CREATE INDEX idx_journal_entries_date ON journal_entries (entry_date); """ ) await db.execute( f""" CREATE TABLE 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, metadata TEXT DEFAULT '{{}}' ); """ ) await db.execute( """ CREATE INDEX idx_entry_lines_journal_entry ON entry_lines (journal_entry_id); """ ) await db.execute( """ CREATE INDEX idx_entry_lines_account ON 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 accounts (id, name, account_type, description) VALUES (:id, :name, :type, :description) """, {"id": acc_id, "name": name, "type": acc_type, "description": desc} )