Files
Torsten Schulz (local) 0e539710c0 feat: Add password reset functionality with request and reset forms
feat: Implement price list import feature with preview and apply options

feat: Create price rules management page with CRUD operations

feat: Develop quotes management page with itemized quotes and status tracking

feat: Introduce organization registration page for new users

feat: Build suppliers management page with detailed supplier information

feat: Create users management page for inviting and managing roles

chore: Add TypeScript configuration for improved type checking

chore: Set up Vite configuration for development server and API proxy

chore: Add Vite environment type definitions for better TypeScript support
2026-06-02 15:28:38 +02:00

83 lines
3.0 KiB
SQL

-- Template migration for each organization schema.
-- Replace {schema} with the real schema name, e.g. company_<organization_id>.
create table if not exists {schema}.quotes (
id uuid primary key,
quote_number text not null unique,
customer_id uuid not null references {schema}.customers(id),
status text not null default 'draft',
valid_until date,
cash_discount_term_id uuid references {schema}.cash_discount_terms(id),
customer_discount_percent numeric(7, 4) not null default 0,
notes_ciphertext bytea,
notes_nonce bytea,
notes_key_id text,
created_by_user_id uuid,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
constraint quotes_status_valid check (
status in ('draft', 'sent', 'accepted', 'rejected', 'expired', 'cancelled')
),
constraint quotes_customer_discount_valid check (
customer_discount_percent >= 0 and customer_discount_percent <= 100
),
constraint quotes_notes_encryption_complete check (
(
notes_ciphertext is null
and notes_nonce is null
and notes_key_id is null
)
or (
notes_ciphertext is not null
and notes_nonce is not null
and notes_key_id is not null
)
)
);
create index if not exists idx_quotes_customer_status
on {schema}.quotes (customer_id, status);
create table if not exists {schema}.quote_items (
id uuid primary key,
quote_id uuid not null references {schema}.quotes(id) on delete cascade,
line_number integer not null,
item_id uuid not null references {schema}.items(id),
description_ciphertext bytea,
description_nonce bytea,
description_key_id text,
quantity numeric(14, 4) not null,
unit_price numeric(14, 4) not null,
original_unit_price numeric(14, 4),
discount_percent numeric(7, 4) not null default 0,
price_overridden boolean not null default false,
tax_rate numeric(7, 4) not null,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
unique (quote_id, line_number),
constraint quote_items_quantity_positive check (quantity > 0),
constraint quote_items_unit_price_non_negative check (unit_price >= 0),
constraint quote_items_original_price_non_negative check (
original_unit_price is null or original_unit_price >= 0
),
constraint quote_items_discount_valid check (
discount_percent >= 0 and discount_percent <= 100
),
constraint quote_items_tax_rate_non_negative check (tax_rate >= 0),
constraint quote_items_description_encryption_complete check (
(
description_ciphertext is null
and description_nonce is null
and description_key_id is null
)
or (
description_ciphertext is not null
and description_nonce is not null
and description_key_id is not null
)
)
);
create index if not exists idx_quote_items_item
on {schema}.quote_items (item_id);