Files
crm/schema.sql
T

201 lines
6.4 KiB
SQL

CREATE TABLE IF NOT EXISTS settings (
key TEXT PRIMARY KEY,
value TEXT
);
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE COLLATE NOCASE,
password_hash TEXT NOT NULL,
role TEXT NOT NULL DEFAULT 'user',
active INTEGER NOT NULL DEFAULT 1,
created_at TEXT NOT NULL
);
-- Relaties (zoals accounts in EspoCRM): klantbundels (huishouden, familie, bedrijf) en partners
-- (leverancier, aannemer, ...). Contactpersonen hangen eronder met een rol.
CREATE TABLE IF NOT EXISTS relations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
kind TEXT NOT NULL DEFAULT 'klant',
type TEXT DEFAULT '',
name TEXT NOT NULL,
email TEXT DEFAULT '',
phone TEXT DEFAULT '',
website TEXT DEFAULT '',
address TEXT DEFAULT '',
postcode TEXT DEFAULT '',
city TEXT DEFAULT '',
kvk TEXT DEFAULT '',
notes TEXT DEFAULT '',
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_relations_name ON relations(kind, name COLLATE NOCASE);
CREATE TABLE IF NOT EXISTS contacts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL DEFAULT '',
email TEXT DEFAULT '',
phone TEXT DEFAULT '',
company TEXT DEFAULT '',
address TEXT DEFAULT '',
postcode TEXT DEFAULT '',
city TEXT DEFAULT '',
type TEXT NOT NULL DEFAULT 'lead',
status TEXT NOT NULL DEFAULT 'nieuw',
source TEXT DEFAULT '',
value REAL NOT NULL DEFAULT 0,
assigned_user_id INTEGER REFERENCES users(id) ON DELETE SET NULL,
relation_id INTEGER REFERENCES relations(id) ON DELETE SET NULL,
relation_role TEXT DEFAULT '',
portal_token TEXT,
portal_password_hash TEXT,
portal_last_login TEXT,
notes TEXT DEFAULT '',
extra TEXT DEFAULT '{}',
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_contacts_email ON contacts(email COLLATE NOCASE);
CREATE TABLE IF NOT EXISTS activities (
id INTEGER PRIMARY KEY AUTOINCREMENT,
contact_id INTEGER NOT NULL REFERENCES contacts(id) ON DELETE CASCADE,
type TEXT NOT NULL,
body TEXT DEFAULT '',
user_id INTEGER REFERENCES users(id) ON DELETE SET NULL,
created_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS files (
id INTEGER PRIMARY KEY AUTOINCREMENT,
contact_id INTEGER REFERENCES contacts(id) ON DELETE CASCADE,
stored TEXT NOT NULL,
original TEXT NOT NULL,
mime TEXT DEFAULT '',
size INTEGER DEFAULT 0,
created_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS products (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
sku TEXT DEFAULT '',
description TEXT DEFAULT '',
unit TEXT DEFAULT 'stuk',
supplier TEXT DEFAULT '',
supplier_id INTEGER REFERENCES relations(id) ON DELETE SET NULL,
price REAL NOT NULL DEFAULT 0,
vat REAL NOT NULL DEFAULT 21,
image TEXT DEFAULT '',
active INTEGER NOT NULL DEFAULT 1,
created_at TEXT NOT NULL,
updated_at TEXT
);
-- Elke wijziging aan een product (handmatig, import of API), zodat prijsmutaties terug te zien zijn.
CREATE TABLE IF NOT EXISTS product_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
product_id INTEGER NOT NULL REFERENCES products(id) ON DELETE CASCADE,
field TEXT NOT NULL,
old_value TEXT,
new_value TEXT,
source TEXT DEFAULT '',
user_id INTEGER REFERENCES users(id) ON DELETE SET NULL,
created_at TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_product_history ON product_history(product_id, created_at);
CREATE TABLE IF NOT EXISTS quotes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
number TEXT UNIQUE NOT NULL,
contact_id INTEGER REFERENCES contacts(id) ON DELETE SET NULL,
status TEXT NOT NULL DEFAULT 'concept',
title TEXT DEFAULT '',
date TEXT NOT NULL,
valid_until TEXT,
intro TEXT DEFAULT '',
notes TEXT DEFAULT '',
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS quote_lines (
id INTEGER PRIMARY KEY AUTOINCREMENT,
quote_id INTEGER NOT NULL REFERENCES quotes(id) ON DELETE CASCADE,
position INTEGER NOT NULL DEFAULT 0,
product_id INTEGER,
description TEXT NOT NULL DEFAULT '',
qty REAL NOT NULL DEFAULT 1,
unit TEXT DEFAULT '',
price REAL NOT NULL DEFAULT 0,
vat REAL NOT NULL DEFAULT 21
);
CREATE TABLE IF NOT EXISTS emails (
id INTEGER PRIMARY KEY AUTOINCREMENT,
uid TEXT UNIQUE,
message_id TEXT DEFAULT '',
direction TEXT NOT NULL DEFAULT 'in',
contact_id INTEGER REFERENCES contacts(id) ON DELETE SET NULL,
from_name TEXT DEFAULT '',
from_addr TEXT DEFAULT '',
to_addr TEXT DEFAULT '',
subject TEXT DEFAULT '',
body TEXT DEFAULT '',
date TEXT NOT NULL,
is_read INTEGER NOT NULL DEFAULT 0,
archived INTEGER NOT NULL DEFAULT 0,
cc TEXT DEFAULT '',
attachments TEXT DEFAULT ''
);
CREATE INDEX IF NOT EXISTS idx_emails_from ON emails(from_addr);
-- E-mailtemplates: onderwerp en tekst met velden als {voornaam}, ingevuld bij het opstellen of versturen
-- (MAIL_FIELDS in app.py).
CREATE TABLE IF NOT EXISTS email_templates (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
subject TEXT DEFAULT '',
body TEXT DEFAULT '',
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
contact_id INTEGER REFERENCES contacts(id) ON DELETE CASCADE,
user_id INTEGER REFERENCES users(id) ON DELETE SET NULL,
title TEXT NOT NULL,
due_date TEXT,
done INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL
);
-- Agenda: één agenda per gebruiker, ook via CalDAV (/dav/). `ics` is het kalenderobject zoals een
-- agenda-app het stuurde (of zoals de CRM het maakte), de losse kolommen zijn daaruit gehaald voor weergave.
CREATE TABLE IF NOT EXISTS events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
contact_id INTEGER REFERENCES contacts(id) ON DELETE SET NULL,
uid TEXT NOT NULL,
href TEXT NOT NULL,
title TEXT NOT NULL DEFAULT '',
location TEXT DEFAULT '',
description TEXT DEFAULT '',
starts_at TEXT NOT NULL,
ends_at TEXT NOT NULL,
all_day INTEGER NOT NULL DEFAULT 0,
rrule TEXT DEFAULT '',
exdates TEXT DEFAULT '',
ics TEXT NOT NULL,
etag TEXT NOT NULL,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_events_href ON events(user_id, href);
CREATE UNIQUE INDEX IF NOT EXISTS idx_events_uid ON events(user_id, uid);
CREATE INDEX IF NOT EXISTS idx_events_start ON events(starts_at);
CREATE INDEX IF NOT EXISTS idx_events_contact ON events(contact_id);