create table if not exists public.commerce_reconciliation_issues ( id uuid primary key default gen_random_uuid(), tenant_id uuid not null references public.tenants(id) on delete cascade, batch_id uuid references public.commerce_reconciliation_batches(id) on delete set null, item_id uuid references public.commerce_reconciliation_items(id) on delete set null, issue_no text not null, provider text not null, transaction_type text not null check (transaction_type in ('payment', 'refund')), issue_code text, match_status text not null check (match_status in ('amount_mismatch', 'status_mismatch', 'missing_local', 'missing_provider', 'duplicate')), severity text not null default 'warning' check (severity in ('info', 'warning', 'error', 'critical')), status text not null default 'open' check (status in ('open', 'investigating', 'resolved', 'ignored', 'escalated')), resolution_type text not null default 'none' check (resolution_type in ('none', 'provider_confirmed', 'local_corrected', 'manual_adjustment', 'false_positive', 'duplicate', 'write_off')), order_id uuid references public.orders(id) on delete set null, payment_id uuid references public.payments(id) on delete set null, refund_request_id uuid references public.commerce_refund_requests(id) on delete set null, order_no text, refund_no text, provider_trade_no text, provider_refund_no text, amount_cents integer not null default 0 check (amount_cents >= 0), refund_amount_cents integer not null default 0 check (refund_amount_cents >= 0), assigned_to uuid references public.platform_users(id) on delete set null, created_by uuid references public.platform_users(id) on delete set null, resolved_by uuid references public.platform_users(id) on delete set null, resolved_at timestamptz, due_at timestamptz, summary text, resolution_note text, metadata jsonb not null default '{}'::jsonb, created_at timestamptz not null default now(), updated_at timestamptz not null default now(), unique (tenant_id, issue_no) ); create table if not exists public.commerce_reconciliation_issue_events ( id uuid primary key default gen_random_uuid(), tenant_id uuid not null references public.tenants(id) on delete cascade, issue_id uuid not null references public.commerce_reconciliation_issues(id) on delete cascade, from_status text, to_status text, event_type text not null, actor_user_id uuid references public.platform_users(id) on delete set null, note text, details jsonb not null default '{}'::jsonb, created_at timestamptz not null default now(), check (from_status is null or from_status in ('open', 'investigating', 'resolved', 'ignored', 'escalated')), check (to_status is null or to_status in ('open', 'investigating', 'resolved', 'ignored', 'escalated')) ); create unique index if not exists idx_commerce_recon_issues_active_item on public.commerce_reconciliation_issues(tenant_id, item_id) where item_id is not null and status in ('open', 'investigating', 'escalated'); create index if not exists idx_commerce_recon_issues_tenant_status on public.commerce_reconciliation_issues(tenant_id, status, severity, created_at desc); create index if not exists idx_commerce_recon_issues_assigned on public.commerce_reconciliation_issues(tenant_id, assigned_to, status, due_at); create index if not exists idx_commerce_recon_issues_batch on public.commerce_reconciliation_issues(tenant_id, batch_id, status, created_at desc); create index if not exists idx_commerce_recon_issues_order on public.commerce_reconciliation_issues(tenant_id, order_no, created_at desc); create index if not exists idx_commerce_recon_issues_payment on public.commerce_reconciliation_issues(tenant_id, payment_id, created_at desc); create index if not exists idx_commerce_recon_issue_events_issue on public.commerce_reconciliation_issue_events(tenant_id, issue_id, created_at desc); alter table public.commerce_reconciliation_issues enable row level security; alter table public.commerce_reconciliation_issue_events enable row level security; drop policy if exists tenant_isolation on public.commerce_reconciliation_issues; create policy tenant_isolation on public.commerce_reconciliation_issues for all using (tenant_id = app.current_tenant_id() or app.is_platform_admin()) with check (tenant_id = app.current_tenant_id() or app.is_platform_admin()); drop policy if exists tenant_isolation on public.commerce_reconciliation_issue_events; create policy tenant_isolation on public.commerce_reconciliation_issue_events for all using (tenant_id = app.current_tenant_id() or app.is_platform_admin()) with check (tenant_id = app.current_tenant_id() or app.is_platform_admin()); drop trigger if exists set_updated_at on public.commerce_reconciliation_issues; create trigger set_updated_at before update on public.commerce_reconciliation_issues for each row execute function app.touch_updated_at();