Files
accounted/supabase/migrations/20260721101500_harden_tax_assessment_notices.sql
T
Mattsson e11f70b347 Bug/gh issues fiz (#1103)
* refactor: optimize page loading and data fetching

* fix: resolve recurring production runtime errors

* feat: add MCP company and customer updates

* fix: handle year-end tax adjustments

* feat: harden annual report compliance

* fix: expand invoice logo and font support

* fix: sanitize API route error responses

* fix: sanitize user-facing error messages

* feat: persist onboarding and tax assessment notices

* fix: reduce cloud backup audit churn

* feat: refine invoice editor layout

* fix: show saved tax adjustments in INK2

* fix: complete annual report API mappings

* docs: record operational safeguards and decisions

* fix: harden annual report review findings

* fix: adjust column span for description based on VAT registration

* New css class name
2026-07-21 23:00:15 +02:00

105 lines
4.0 KiB
PL/PgSQL

-- Harden tax notice tenant integrity and preserve every reassessment decision.
-- A fiscal year can receive more than one reassessment decision. The decision
-- date is part of the notice identity so repeated POST requests stay
-- idempotent without overwriting an earlier decision.
ALTER TABLE public.tax_assessment_notices
DROP CONSTRAINT tax_assessment_notices_company_period_type_key;
ALTER TABLE public.tax_assessment_notices
ADD CONSTRAINT tax_assessment_notices_company_period_type_date_key
UNIQUE (company_id, fiscal_period_id, decision_type, decision_date);
-- The creator is attribution, not ownership. Company records must survive a
-- user deletion, including when a generated deadline references the notice.
ALTER TABLE public.tax_assessment_notices
ALTER COLUMN user_id DROP NOT NULL;
ALTER TABLE public.tax_assessment_notices
DROP CONSTRAINT tax_assessment_notices_user_id_fkey;
ALTER TABLE public.tax_assessment_notices
ADD CONSTRAINT tax_assessment_notices_user_id_fkey
FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE SET NULL;
-- Company-owned foreign keys must agree on company_id. The additional unique
-- keys are safe because both referenced id columns are already primary keys.
ALTER TABLE public.fiscal_periods
ADD CONSTRAINT fiscal_periods_id_company_id_key UNIQUE (id, company_id);
ALTER TABLE public.tax_assessment_notices
DROP CONSTRAINT tax_assessment_notices_fiscal_period_id_fkey;
ALTER TABLE public.tax_assessment_notices
ADD CONSTRAINT tax_assessment_notices_fiscal_period_company_fkey
FOREIGN KEY (fiscal_period_id, company_id)
REFERENCES public.fiscal_periods(id, company_id) ON DELETE RESTRICT;
ALTER TABLE public.tax_assessment_notices
ADD CONSTRAINT tax_assessment_notices_id_company_id_key UNIQUE (id, company_id);
ALTER TABLE public.deadlines
DROP CONSTRAINT deadlines_tax_assessment_notice_id_fkey;
ALTER TABLE public.deadlines
ADD CONSTRAINT deadlines_tax_assessment_notice_company_fkey
FOREIGN KEY (tax_assessment_notice_id, company_id)
REFERENCES public.tax_assessment_notices(id, company_id) ON DELETE RESTRICT;
-- Keep creator attribution immutable for authenticated PostgREST callers.
CREATE OR REPLACE FUNCTION public.enforce_tax_assessment_notice_attribution()
RETURNS trigger
LANGUAGE plpgsql
SET search_path TO 'public'
AS $function$
BEGIN
IF auth.uid() IS NOT NULL AND NEW.user_id IS DISTINCT FROM OLD.user_id THEN
RAISE EXCEPTION 'Tax assessment notice attribution is immutable'
USING ERRCODE = '42501';
END IF;
RETURN NEW;
END;
$function$;
CREATE TRIGGER enforce_tax_assessment_notice_attribution
BEFORE UPDATE OF user_id ON public.tax_assessment_notices
FOR EACH ROW EXECUTE FUNCTION public.enforce_tax_assessment_notice_attribution();
-- Reads follow the repository-wide membership model. Writes additionally
-- require the active company and a non-viewer role, matching other tenant
-- tables and preventing direct PostgREST writes from bypassing the API guard.
DROP POLICY "insert own-company tax_assessment_notices"
ON public.tax_assessment_notices;
DROP POLICY "update own-company tax_assessment_notices"
ON public.tax_assessment_notices;
DROP POLICY "delete own-company tax_assessment_notices"
ON public.tax_assessment_notices;
CREATE POLICY tax_assessment_notices_insert
ON public.tax_assessment_notices FOR INSERT TO public
WITH CHECK (
company_id = public.current_active_company_id()
AND public.current_user_can_write()
AND user_id = auth.uid()
);
CREATE POLICY tax_assessment_notices_update
ON public.tax_assessment_notices FOR UPDATE TO public
USING (
company_id = public.current_active_company_id()
AND public.current_user_can_write()
)
WITH CHECK (
company_id = public.current_active_company_id()
AND public.current_user_can_write()
);
CREATE POLICY tax_assessment_notices_delete
ON public.tax_assessment_notices FOR DELETE TO public
USING (
company_id = public.current_active_company_id()
AND public.current_user_can_write()
);
NOTIFY pgrst, 'reload schema';