119 lines
7.0 KiB
SQL
119 lines
7.0 KiB
SQL
/*
|
|
* -------------------------------------------------------
|
|
* Finance / SEPA Schema
|
|
* Phase 8: sepa_batches, sepa_items, invoices, invoice_items
|
|
* -------------------------------------------------------
|
|
*/
|
|
|
|
create type public.sepa_batch_type as enum('direct_debit', 'credit_transfer');
|
|
create type public.sepa_batch_status as enum('draft', 'ready', 'submitted', 'executed', 'failed', 'cancelled');
|
|
create type public.sepa_item_status as enum('pending', 'success', 'failed', 'rejected');
|
|
create type public.invoice_status as enum('draft', 'sent', 'paid', 'overdue', 'cancelled', 'credited');
|
|
|
|
-- SEPA batches
|
|
create table if not exists public.sepa_batches (
|
|
id uuid primary key default gen_random_uuid(),
|
|
account_id uuid not null references public.accounts(id) on delete cascade,
|
|
batch_type public.sepa_batch_type not null,
|
|
status public.sepa_batch_status not null default 'draft',
|
|
description text,
|
|
execution_date date not null,
|
|
total_amount numeric(12,2) not null default 0,
|
|
item_count integer not null default 0,
|
|
xml_storage_path text,
|
|
pain_format text not null default 'pain.008.003.02',
|
|
created_by uuid references auth.users(id) on delete set null,
|
|
created_at timestamptz not null default now(),
|
|
updated_at timestamptz not null default now()
|
|
);
|
|
create index ix_sepa_batches_account on public.sepa_batches(account_id);
|
|
alter table public.sepa_batches enable row level security;
|
|
revoke all on public.sepa_batches from authenticated, service_role;
|
|
grant select, insert, update, delete on public.sepa_batches to authenticated;
|
|
grant all on public.sepa_batches to service_role;
|
|
create policy sepa_batches_select on public.sepa_batches for select to authenticated using (public.has_role_on_account(account_id));
|
|
create policy sepa_batches_insert on public.sepa_batches for insert to authenticated with check (public.has_permission(auth.uid(), account_id, 'finance.sepa'::public.app_permissions));
|
|
create policy sepa_batches_update on public.sepa_batches for update to authenticated using (public.has_permission(auth.uid(), account_id, 'finance.sepa'::public.app_permissions));
|
|
create policy sepa_batches_delete on public.sepa_batches for delete to authenticated using (public.has_permission(auth.uid(), account_id, 'finance.sepa'::public.app_permissions));
|
|
|
|
-- SEPA items (individual transactions)
|
|
create table if not exists public.sepa_items (
|
|
id uuid primary key default gen_random_uuid(),
|
|
batch_id uuid not null references public.sepa_batches(id) on delete cascade,
|
|
member_id uuid references public.members(id) on delete set null,
|
|
debtor_name text not null,
|
|
debtor_iban text not null,
|
|
debtor_bic text,
|
|
amount numeric(10,2) not null,
|
|
mandate_id text,
|
|
mandate_date date,
|
|
remittance_info text,
|
|
status public.sepa_item_status not null default 'pending',
|
|
error_message text,
|
|
created_at timestamptz not null default now()
|
|
);
|
|
create index ix_sepa_items_batch on public.sepa_items(batch_id);
|
|
create index ix_sepa_items_member on public.sepa_items(member_id);
|
|
alter table public.sepa_items enable row level security;
|
|
revoke all on public.sepa_items from authenticated, service_role;
|
|
grant select, insert, update, delete on public.sepa_items to authenticated;
|
|
grant all on public.sepa_items to service_role;
|
|
create policy sepa_items_select on public.sepa_items for select to authenticated using (exists (select 1 from public.sepa_batches b where b.id = sepa_items.batch_id and public.has_role_on_account(b.account_id)));
|
|
create policy sepa_items_mutate on public.sepa_items for all to authenticated using (exists (select 1 from public.sepa_batches b where b.id = sepa_items.batch_id and public.has_permission(auth.uid(), b.account_id, 'finance.sepa'::public.app_permissions)));
|
|
|
|
-- Invoices
|
|
create table if not exists public.invoices (
|
|
id uuid primary key default gen_random_uuid(),
|
|
account_id uuid not null references public.accounts(id) on delete cascade,
|
|
invoice_number text not null,
|
|
member_id uuid references public.members(id) on delete set null,
|
|
recipient_name text not null,
|
|
recipient_address text,
|
|
issue_date date not null default current_date,
|
|
due_date date not null,
|
|
status public.invoice_status not null default 'draft',
|
|
subtotal numeric(10,2) not null default 0,
|
|
tax_rate numeric(5,2) not null default 0,
|
|
tax_amount numeric(10,2) not null default 0,
|
|
total_amount numeric(10,2) not null default 0,
|
|
paid_amount numeric(10,2) not null default 0,
|
|
paid_at timestamptz,
|
|
notes text,
|
|
pdf_storage_path text,
|
|
created_by uuid references auth.users(id) on delete set null,
|
|
created_at timestamptz not null default now(),
|
|
updated_at timestamptz not null default now(),
|
|
unique(account_id, invoice_number)
|
|
);
|
|
create index ix_invoices_account on public.invoices(account_id);
|
|
create index ix_invoices_member on public.invoices(member_id);
|
|
create index ix_invoices_status on public.invoices(account_id, status);
|
|
alter table public.invoices enable row level security;
|
|
revoke all on public.invoices from authenticated, service_role;
|
|
grant select, insert, update, delete on public.invoices to authenticated;
|
|
grant all on public.invoices to service_role;
|
|
create policy invoices_select on public.invoices for select to authenticated using (public.has_role_on_account(account_id));
|
|
create policy invoices_insert on public.invoices for insert to authenticated with check (public.has_permission(auth.uid(), account_id, 'finance.write'::public.app_permissions));
|
|
create policy invoices_update on public.invoices for update to authenticated using (public.has_permission(auth.uid(), account_id, 'finance.write'::public.app_permissions));
|
|
create policy invoices_delete on public.invoices for delete to authenticated using (public.has_permission(auth.uid(), account_id, 'finance.write'::public.app_permissions));
|
|
create trigger trg_invoices_updated_at before update on public.invoices for each row execute function public.update_account_settings_timestamp();
|
|
|
|
-- Invoice line items
|
|
create table if not exists public.invoice_items (
|
|
id uuid primary key default gen_random_uuid(),
|
|
invoice_id uuid not null references public.invoices(id) on delete cascade,
|
|
description text not null,
|
|
quantity numeric(10,2) not null default 1,
|
|
unit_price numeric(10,2) not null,
|
|
total_price numeric(10,2) not null,
|
|
sort_order integer not null default 0,
|
|
created_at timestamptz not null default now()
|
|
);
|
|
create index ix_invoice_items_invoice on public.invoice_items(invoice_id);
|
|
alter table public.invoice_items enable row level security;
|
|
revoke all on public.invoice_items from authenticated, service_role;
|
|
grant select, insert, update, delete on public.invoice_items to authenticated;
|
|
grant all on public.invoice_items to service_role;
|
|
create policy invoice_items_select on public.invoice_items for select to authenticated using (exists (select 1 from public.invoices i where i.id = invoice_items.invoice_id and public.has_role_on_account(i.account_id)));
|
|
create policy invoice_items_mutate on public.invoice_items for all to authenticated using (exists (select 1 from public.invoices i where i.id = invoice_items.invoice_id and public.has_permission(auth.uid(), i.account_id, 'finance.write'::public.app_permissions)));
|