refactor: remove obsolete member management API module
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
-- =====================================================
|
||||
-- SEPA Data Deduplication (Phase 1)
|
||||
--
|
||||
-- Problem: members table has inline SEPA fields (iban, bic,
|
||||
-- account_holder, sepa_mandate_id, sepa_mandate_date,
|
||||
-- sepa_mandate_status, sepa_mandate_sequence, sepa_bank_name)
|
||||
-- AND a separate sepa_mandates table. sepa_mandate_id is text,
|
||||
-- not a FK to sepa_mandates(id) which is uuid. Data diverges.
|
||||
--
|
||||
-- Fix: Add proper primary_mandate_id FK, migrate inline data
|
||||
-- to sepa_mandates rows, rewrite RPCs to read from sepa_mandates.
|
||||
-- Inline columns are kept read-only for backward compat (phase 2 drops them).
|
||||
-- =====================================================
|
||||
|
||||
-- Step 1: Add proper FK column pointing to the primary mandate
|
||||
ALTER TABLE public.members
|
||||
ADD COLUMN IF NOT EXISTS primary_mandate_id uuid
|
||||
REFERENCES public.sepa_mandates(id) ON DELETE SET NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS ix_members_primary_mandate
|
||||
ON public.members(primary_mandate_id)
|
||||
WHERE primary_mandate_id IS NOT NULL;
|
||||
|
||||
-- Step 2: For members with inline SEPA data but no sepa_mandates row, create one
|
||||
DO $$
|
||||
DECLARE
|
||||
r record;
|
||||
v_mandate_id uuid;
|
||||
BEGIN
|
||||
FOR r IN
|
||||
SELECT m.id AS member_id, m.account_id,
|
||||
m.iban, m.bic, m.account_holder,
|
||||
m.first_name, m.last_name,
|
||||
m.sepa_mandate_id, m.sepa_mandate_date,
|
||||
m.sepa_mandate_status, m.sepa_mandate_reference,
|
||||
m.sepa_mandate_sequence, m.sepa_bank_name
|
||||
FROM public.members m
|
||||
WHERE m.iban IS NOT NULL AND m.iban != ''
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM public.sepa_mandates sm WHERE sm.member_id = m.id
|
||||
)
|
||||
LOOP
|
||||
INSERT INTO public.sepa_mandates (
|
||||
member_id, account_id, mandate_reference, iban, bic,
|
||||
account_holder, mandate_date, status, sequence, is_primary, notes
|
||||
) VALUES (
|
||||
r.member_id,
|
||||
r.account_id,
|
||||
COALESCE(NULLIF(r.sepa_mandate_reference, ''), NULLIF(r.sepa_mandate_id, ''), 'MIGRATED-' || r.member_id::text),
|
||||
r.iban,
|
||||
r.bic,
|
||||
COALESCE(NULLIF(r.account_holder, ''), NULLIF(TRIM(COALESCE(r.first_name, '') || ' ' || COALESCE(r.last_name, '')), ''), 'Unbekannt'),
|
||||
COALESCE(r.sepa_mandate_date, current_date),
|
||||
COALESCE(r.sepa_mandate_status, 'pending'::public.sepa_mandate_status),
|
||||
COALESCE(NULLIF(r.sepa_mandate_sequence, ''), 'RCUR'),
|
||||
true,
|
||||
CASE WHEN r.sepa_bank_name IS NOT NULL AND r.sepa_bank_name != ''
|
||||
THEN 'Bank: ' || r.sepa_bank_name
|
||||
ELSE NULL
|
||||
END
|
||||
)
|
||||
RETURNING id INTO v_mandate_id;
|
||||
|
||||
UPDATE public.members SET primary_mandate_id = v_mandate_id WHERE id = r.member_id;
|
||||
END LOOP;
|
||||
END $$;
|
||||
|
||||
-- Step 3: For members that already have sepa_mandates rows, link the primary one
|
||||
UPDATE public.members m
|
||||
SET primary_mandate_id = sm.id
|
||||
FROM public.sepa_mandates sm
|
||||
WHERE sm.member_id = m.id
|
||||
AND sm.is_primary = true
|
||||
AND m.primary_mandate_id IS NULL;
|
||||
|
||||
-- If no mandate marked as primary, pick the most recent active one
|
||||
UPDATE public.members m
|
||||
SET primary_mandate_id = (
|
||||
SELECT sm.id FROM public.sepa_mandates sm
|
||||
WHERE sm.member_id = m.id
|
||||
ORDER BY
|
||||
CASE WHEN sm.status = 'active' THEN 0 ELSE 1 END,
|
||||
sm.created_at DESC
|
||||
LIMIT 1
|
||||
)
|
||||
WHERE m.primary_mandate_id IS NULL
|
||||
AND EXISTS (SELECT 1 FROM public.sepa_mandates sm WHERE sm.member_id = m.id);
|
||||
|
||||
-- Step 4: Rewrite list_hierarchy_sepa_eligible_members to read from sepa_mandates
|
||||
CREATE OR REPLACE FUNCTION public.list_hierarchy_sepa_eligible_members(
|
||||
root_account_id uuid,
|
||||
p_account_filter uuid DEFAULT NULL
|
||||
)
|
||||
RETURNS TABLE (
|
||||
member_id uuid,
|
||||
account_id uuid,
|
||||
account_name varchar,
|
||||
first_name text,
|
||||
last_name text,
|
||||
iban text,
|
||||
bic text,
|
||||
account_holder text,
|
||||
mandate_id text,
|
||||
mandate_date date,
|
||||
dues_amount numeric
|
||||
)
|
||||
LANGUAGE plpgsql
|
||||
SECURITY DEFINER
|
||||
SET search_path = ''
|
||||
AS $$
|
||||
BEGIN
|
||||
IF NOT public.has_role_on_account(root_account_id) THEN
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
RETURN QUERY
|
||||
SELECT
|
||||
m.id AS member_id,
|
||||
m.account_id,
|
||||
a.name AS account_name,
|
||||
m.first_name,
|
||||
m.last_name,
|
||||
sm.iban,
|
||||
sm.bic,
|
||||
sm.account_holder,
|
||||
sm.mandate_reference AS mandate_id,
|
||||
sm.mandate_date,
|
||||
COALESCE(dc.amount, 0) AS dues_amount
|
||||
FROM public.members m
|
||||
JOIN public.accounts a ON a.id = m.account_id
|
||||
JOIN public.sepa_mandates sm ON sm.id = m.primary_mandate_id
|
||||
LEFT JOIN public.dues_categories dc ON dc.id = m.dues_category_id
|
||||
WHERE m.account_id IN (SELECT d FROM public.get_account_descendants(root_account_id) d)
|
||||
AND m.status = 'active'
|
||||
AND sm.iban IS NOT NULL
|
||||
AND sm.status = 'active'
|
||||
AND (p_account_filter IS NULL OR m.account_id = p_account_filter)
|
||||
ORDER BY a.name, m.last_name, m.first_name;
|
||||
END;
|
||||
$$;
|
||||
|
||||
-- Step 5: Add partial index for fast SEPA-eligible lookups
|
||||
CREATE INDEX IF NOT EXISTS ix_sepa_mandates_active_primary
|
||||
ON public.sepa_mandates(member_id)
|
||||
WHERE status = 'active' AND is_primary = true;
|
||||
|
||||
-- Note: Inline SEPA columns (iban, bic, account_holder, sepa_mandate_id,
|
||||
-- sepa_mandate_date, sepa_mandate_status, sepa_mandate_sequence, sepa_bank_name)
|
||||
-- are kept for read-only backward compatibility. Phase 2 migration will drop them
|
||||
-- after all code paths are migrated to use sepa_mandates via primary_mandate_id.
|
||||
Reference in New Issue
Block a user