109 lines
4.5 KiB
SQL
109 lines
4.5 KiB
SQL
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
|
|
|
CREATE TABLE IF NOT EXISTS customers (
|
|
customer_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
first_name TEXT NOT NULL,
|
|
last_name TEXT NOT NULL,
|
|
email TEXT UNIQUE,
|
|
phone TEXT,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS vehicles (
|
|
vehicle_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
customer_id UUID NOT NULL REFERENCES customers(customer_id) ON DELETE CASCADE,
|
|
registration_number TEXT NOT NULL UNIQUE,
|
|
make TEXT NOT NULL,
|
|
model TEXT NOT NULL,
|
|
model_year INTEGER CHECK (model_year BETWEEN 1886 AND EXTRACT(YEAR FROM CURRENT_DATE)::INTEGER + 1),
|
|
engine TEXT,
|
|
transmission TEXT,
|
|
fuel_type TEXT,
|
|
color TEXT,
|
|
vin CHAR(17) UNIQUE,
|
|
mileage INTEGER NOT NULL DEFAULT 0 CHECK (mileage >= 0),
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS employees (
|
|
employee_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
first_name TEXT NOT NULL,
|
|
last_name TEXT NOT NULL,
|
|
role TEXT NOT NULL CHECK (role IN ('technician', 'service_advisor', 'manager')),
|
|
email TEXT UNIQUE,
|
|
active BOOLEAN NOT NULL DEFAULT TRUE
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS appointments (
|
|
appointment_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
vehicle_id UUID NOT NULL REFERENCES vehicles(vehicle_id) ON DELETE CASCADE,
|
|
employee_id UUID REFERENCES employees(employee_id) ON DELETE SET NULL,
|
|
scheduled_at TIMESTAMPTZ NOT NULL,
|
|
reason TEXT NOT NULL,
|
|
status TEXT NOT NULL DEFAULT 'scheduled'
|
|
CHECK (status IN ('scheduled', 'confirmed', 'completed', 'cancelled', 'no_show')),
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS service_orders (
|
|
service_order_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
vehicle_id UUID NOT NULL REFERENCES vehicles(vehicle_id) ON DELETE RESTRICT,
|
|
assigned_employee_id UUID REFERENCES employees(employee_id) ON DELETE SET NULL,
|
|
opened_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
closed_at TIMESTAMPTZ,
|
|
complaint TEXT NOT NULL,
|
|
service_date DATE NOT NULL DEFAULT CURRENT_DATE,
|
|
diagnosis TEXT,
|
|
status TEXT NOT NULL DEFAULT 'open'
|
|
CHECK (status IN ('open', 'in_progress', 'waiting_for_parts', 'ready', 'closed', 'cancelled')),
|
|
CHECK (closed_at IS NULL OR closed_at >= opened_at)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS service_order_items (
|
|
item_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
service_order_id UUID NOT NULL REFERENCES service_orders(service_order_id) ON DELETE CASCADE,
|
|
item_type TEXT NOT NULL CHECK (item_type IN ('labor', 'part')),
|
|
description TEXT NOT NULL,
|
|
part_number TEXT,
|
|
labor_time_minutes INTEGER CHECK (labor_time_minutes IS NULL OR labor_time_minutes > 0),
|
|
quantity NUMERIC(10, 2) NOT NULL DEFAULT 1 CHECK (quantity > 0),
|
|
unit_price NUMERIC(12, 2) NOT NULL CHECK (unit_price >= 0),
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS invoices (
|
|
invoice_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
service_order_id UUID NOT NULL UNIQUE REFERENCES service_orders(service_order_id) ON DELETE RESTRICT,
|
|
issued_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
due_at DATE,
|
|
status TEXT NOT NULL DEFAULT 'unpaid'
|
|
CHECK (status IN ('draft', 'unpaid', 'paid', 'void')),
|
|
tax_rate NUMERIC(5, 2) NOT NULL DEFAULT 0 CHECK (tax_rate >= 0 AND tax_rate <= 100)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS app_users (
|
|
user_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
username TEXT NOT NULL UNIQUE,
|
|
display_name TEXT NOT NULL,
|
|
email TEXT UNIQUE,
|
|
role TEXT NOT NULL DEFAULT 'viewer'
|
|
CHECK (role IN ('admin', 'service_advisor', 'technician', 'viewer')),
|
|
can_read BOOLEAN NOT NULL DEFAULT TRUE,
|
|
can_add BOOLEAN NOT NULL DEFAULT FALSE,
|
|
can_delete BOOLEAN NOT NULL DEFAULT FALSE,
|
|
password_hash TEXT,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_vehicles_customer_id ON vehicles(customer_id);
|
|
CREATE INDEX IF NOT EXISTS idx_appointments_scheduled_at ON appointments(scheduled_at);
|
|
CREATE INDEX IF NOT EXISTS idx_service_orders_vehicle_id ON service_orders(vehicle_id);
|
|
CREATE INDEX IF NOT EXISTS idx_service_orders_status ON service_orders(status);
|
|
|
|
INSERT INTO customers (first_name, last_name, email, phone)
|
|
VALUES ('Alex', 'Morgan', 'alex.morgan@example.com', '+1-555-0100')
|
|
ON CONFLICT (email) DO NOTHING;
|
|
|
|
INSERT INTO app_users (username, display_name, role, can_read, can_add, can_delete)
|
|
VALUES ('admin', 'Workshop administrator', 'admin', TRUE, TRUE, TRUE)
|
|
ON CONFLICT (username) DO NOTHING; |