Initial state for GitNexus analysis
This commit is contained in:
118
apps/web/supabase/migrations/20260407000001_finance_sepa.sql
Normal file
118
apps/web/supabase/migrations/20260407000001_finance_sepa.sql
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* -------------------------------------------------------
|
||||
* 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)));
|
||||
Reference in New Issue
Block a user