Files
boc/landvex-admin-v2/schema-full.sql
T

305 lines
14 KiB
SQL
Raw Normal View History

-- ═══════════════════════════════════════════════════════════════════════════
-- AAMOS Admin v2 — Fullständigt databasschema
-- CRM, Fakturering, Bokföring, Automation, Övervakning
-- ═══════════════════════════════════════════════════════════════════════════
-- ── Customers (Kunder) ─────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS billing_customers (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
customer_type TEXT NOT NULL DEFAULT 'company', -- 'company'|'individual'
org_nr TEXT,
name TEXT NOT NULL,
email TEXT,
phone TEXT,
address TEXT,
postal_code TEXT,
city TEXT,
country TEXT DEFAULT 'SE',
reference TEXT,
notes TEXT,
status TEXT NOT NULL DEFAULT 'active', -- 'active'|'inactive'|'prospect'
payment_terms_days INTEGER DEFAULT 30,
vat_number TEXT,
-- Landvex Platform integration
platform_customer_id TEXT,
platform_synced_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_customers_status ON billing_customers (status);
CREATE INDEX IF NOT EXISTS idx_customers_org_nr ON billing_customers (org_nr);
-- ── Leads ──────────────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS crm_leads (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
email TEXT,
phone TEXT,
company TEXT,
source TEXT NOT NULL DEFAULT 'web', -- 'web'|'referral'|'cold_call'|'event'|'other'
status TEXT NOT NULL DEFAULT 'new', -- 'new'|'contacted'|'qualified'|'converted'|'lost'
notes TEXT,
converted_at TIMESTAMPTZ,
converted_to_customer_id UUID REFERENCES billing_customers(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_leads_status ON crm_leads (status);
CREATE INDEX IF NOT EXISTS idx_leads_source ON crm_leads (source);
CREATE UNIQUE INDEX IF NOT EXISTS idx_leads_email ON crm_leads (email);
-- ── Agreements (Avtal) ─────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS billing_agreements (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
agreement_number TEXT NOT NULL UNIQUE,
customer_id UUID NOT NULL REFERENCES billing_customers(id),
agreement_type TEXT NOT NULL DEFAULT 'kommersiellt', -- 'kommunalt'|'kommersiellt'|'internt'
status TEXT NOT NULL DEFAULT 'draft', -- 'draft'|'active'|'suspended'|'terminated'|'expired'
title TEXT NOT NULL,
description TEXT,
start_date DATE NOT NULL,
end_date DATE,
auto_renew BOOLEAN NOT NULL DEFAULT FALSE,
renewal_period_months INTEGER,
billing_frequency TEXT NOT NULL DEFAULT 'monthly', -- 'monthly'|'quarterly'|'semi_annual'|'annual'|'one_time'
billing_day INTEGER NOT NULL DEFAULT 1,
payment_terms_days INTEGER NOT NULL DEFAULT 30,
amount NUMERIC(18,2) NOT NULL DEFAULT 0,
currency TEXT NOT NULL DEFAULT 'SEK',
vat_rate NUMERIC(5,2) NOT NULL DEFAULT 25.0,
next_invoice_date DATE,
last_invoice_date DATE,
-- Landvex Platform
platform_agreement_id TEXT,
platform_synced_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_agreements_customer ON billing_agreements (customer_id);
CREATE INDEX IF NOT EXISTS idx_agreements_status ON billing_agreements (status);
-- ── Invoices (Fakturor) ────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS billing_invoices (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
invoice_number TEXT NOT NULL UNIQUE,
customer_id UUID NOT NULL REFERENCES billing_customers(id),
agreement_id UUID REFERENCES billing_agreements(id),
invoice_type TEXT NOT NULL DEFAULT 'standard', -- 'standard'|'credit'|'proforma'|'reminder'
status TEXT NOT NULL DEFAULT 'draft', -- 'draft'|'sent'|'paid'|'partially_paid'|'overdue'|'cancelled'|'credited'
customer_name TEXT NOT NULL,
customer_address TEXT,
customer_postal TEXT,
customer_city TEXT,
customer_email TEXT,
customer_reference TEXT,
invoice_date DATE NOT NULL,
due_date DATE NOT NULL,
delivery_date DATE,
sent_at TIMESTAMPTZ,
paid_at TIMESTAMPTZ,
credited_at TIMESTAMPTZ,
currency TEXT NOT NULL DEFAULT 'SEK',
subtotal NUMERIC(18,2) NOT NULL DEFAULT 0,
vat_total NUMERIC(18,2) NOT NULL DEFAULT 0,
total NUMERIC(18,2) NOT NULL DEFAULT 0,
amount_paid NUMERIC(18,2) NOT NULL DEFAULT 0,
amount_due NUMERIC(18,2) NOT NULL DEFAULT 0,
vat_specification JSONB NOT NULL DEFAULT '{}',
-- Ledger integration
journal_entry_id UUID,
ledger_posted_at TIMESTAMPTZ,
reminder_count INTEGER NOT NULL DEFAULT 0,
last_reminder_at TIMESTAMPTZ,
reminder_fee NUMERIC(18,2) DEFAULT 0,
interest_fee NUMERIC(18,2) DEFAULT 0,
pdf_generated_at TIMESTAMPTZ,
pdf_url TEXT,
-- Landvex Platform
platform_invoice_id TEXT,
platform_synced_at TIMESTAMPTZ,
notes TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_invoices_customer ON billing_invoices (customer_id);
CREATE INDEX IF NOT EXISTS idx_invoices_status ON billing_invoices (status);
CREATE INDEX IF NOT EXISTS idx_invoices_dates ON billing_invoices (invoice_date, due_date);
CREATE INDEX IF NOT EXISTS idx_invoices_overdue ON billing_invoices (status, due_date) WHERE status IN ('sent', 'partially_paid');
-- ── Invoice Lines ──────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS billing_invoice_lines (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
invoice_id UUID NOT NULL REFERENCES billing_invoices(id) ON DELETE CASCADE,
line_number INTEGER NOT NULL,
description TEXT NOT NULL,
quantity NUMERIC(12,2) NOT NULL DEFAULT 1,
unit TEXT,
unit_price NUMERIC(18,2) NOT NULL,
line_total NUMERIC(18,2) NOT NULL,
vat_rate NUMERIC(5,2) NOT NULL,
vat_amount NUMERIC(18,2) NOT NULL,
line_total_incl_vat NUMERIC(18,2) NOT NULL,
revenue_account TEXT NOT NULL DEFAULT '3000',
cost_center TEXT,
project_code TEXT,
UNIQUE (invoice_id, line_number)
);
-- ── Payments (Inbetalningar) ───────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS billing_payments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
invoice_id UUID NOT NULL REFERENCES billing_invoices(id),
payment_date DATE NOT NULL,
amount NUMERIC(18,2) NOT NULL,
currency TEXT NOT NULL DEFAULT 'SEK',
payment_method TEXT NOT NULL, -- 'bank_transfer'|'swish'|'card'|'cash'|'autogiro'|'other'
payment_reference TEXT,
bank_transaction_id TEXT,
reconciliation_status TEXT NOT NULL DEFAULT 'unreconciled', -- 'unreconciled'|'matched'|'reconciled'
reconciled_at TIMESTAMPTZ,
journal_entry_id UUID,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_payments_invoice ON billing_payments (invoice_id);
CREATE INDEX IF NOT EXISTS idx_payments_reconciliation ON billing_payments (reconciliation_status);
-- ── Automations ────────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS automations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
description TEXT,
trigger_type TEXT NOT NULL, -- 'scheduled'|'event'|'manual'
frequency TEXT, -- 'daily'|'weekly'|'monthly'|'quarterly'
action TEXT NOT NULL, -- 'create_invoice'|'send_reminder'|'export_report'|'backup'
action_config JSONB NOT NULL DEFAULT '{}',
is_active BOOLEAN NOT NULL DEFAULT TRUE,
last_run_at TIMESTAMPTZ,
last_run_status TEXT,
last_run_result JSONB,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- ── Automation Logs ────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS automation_logs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
automation_id UUID NOT NULL REFERENCES automations(id),
status TEXT NOT NULL, -- 'success'|'failed'|'running'
result JSONB,
executed_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- ── Settings ───────────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS settings (
id INTEGER PRIMARY KEY DEFAULT 1,
company_name TEXT NOT NULL DEFAULT 'LandveX AB',
org_nr TEXT DEFAULT '559141-7042',
vat_nr TEXT DEFAULT 'SE559141704201',
address TEXT,
postal_code TEXT,
city TEXT,
payment_terms_days INTEGER DEFAULT 30,
default_vat_rate NUMERIC(5,2) DEFAULT 25.0,
bank_account TEXT,
bankgiro TEXT,
postgiro TEXT,
swish_number TEXT,
logo_url TEXT,
email_from TEXT,
email_reply_to TEXT,
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
INSERT INTO settings (id) VALUES (1) ON CONFLICT (id) DO NOTHING;
-- ── Bank Transactions (for reconciliation) ─────────────────────────────────
CREATE TABLE IF NOT EXISTS bank_transactions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
transaction_date DATE NOT NULL,
description TEXT,
amount NUMERIC(18,2) NOT NULL,
currency TEXT NOT NULL DEFAULT 'SEK',
reference TEXT,
bank_account TEXT,
matched_at TIMESTAMPTZ,
matched_by TEXT,
reconciled_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- ── Mail Messages ──────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS mail_messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
from_email TEXT NOT NULL,
from_name TEXT,
to_email TEXT,
subject TEXT,
body TEXT,
folder TEXT NOT NULL DEFAULT 'inbox', -- 'inbox'|'sent'|'archive'|'trash'
status TEXT NOT NULL DEFAULT 'unread', -- 'unread'|'read'|'replied'|'archived'
source TEXT, -- 'quixzoom_waitlist'|'landvex_contact'|'aamos_contact'|'manual'|'manual_reply'
source_url TEXT,
lead_id UUID REFERENCES crm_leads(id),
in_reply_to UUID REFERENCES mail_messages(id),
read_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_mail_folder ON mail_messages (folder);
CREATE INDEX IF NOT EXISTS idx_mail_status ON mail_messages (status);
CREATE INDEX IF NOT EXISTS idx_mail_source ON mail_messages (source);
CREATE INDEX IF NOT EXISTS idx_mail_lead ON mail_messages (lead_id);
CREATE INDEX IF NOT EXISTS idx_mail_created ON mail_messages (created_at DESC);
-- ── Audit Log ──────────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS audit_log (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id TEXT,
entity_type TEXT NOT NULL, -- 'customer'|'invoice'|'payment'|'agreement'|'automation'
entity_id TEXT NOT NULL,
action TEXT NOT NULL, -- 'created'|'updated'|'deleted'|'sent'|'paid'
before_state JSONB,
after_state JSONB,
ip_address TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- ── Landvex Platform Sync Queue ────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS platform_sync_queue (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
entity_type TEXT NOT NULL, -- 'customer'|'agreement'|'invoice'
entity_id UUID NOT NULL,
action TEXT NOT NULL, -- 'create'|'update'|'delete'
status TEXT NOT NULL DEFAULT 'pending', -- 'pending'|'processing'|'completed'|'failed'
error_message TEXT,
retry_count INTEGER DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
processed_at TIMESTAMPTZ
);