-- Migration 178: Link customers and vendors (many-to-many) -- Created: 2026-04-13 CREATE TABLE IF NOT EXISTS customer_vendor_links ( id SERIAL PRIMARY KEY, customer_id INTEGER NOT NULL REFERENCES customers(id) ON DELETE CASCADE, vendor_id INTEGER NOT NULL REFERENCES vendors(id) ON DELETE CASCADE, relationship_type VARCHAR(50) NOT NULL DEFAULT 'supplier', created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, UNIQUE (customer_id, vendor_id) ); DO $$ BEGIN IF NOT EXISTS ( SELECT 1 FROM pg_constraint WHERE conname = 'chk_customer_vendor_links_relationship_type' ) THEN ALTER TABLE customer_vendor_links ADD CONSTRAINT chk_customer_vendor_links_relationship_type CHECK (relationship_type IN ('supplier', 'reseller', 'partner')); END IF; END $$; CREATE INDEX IF NOT EXISTS idx_customer_vendor_links_customer_id ON customer_vendor_links(customer_id); CREATE INDEX IF NOT EXISTS idx_customer_vendor_links_vendor_id ON customer_vendor_links(vendor_id); CREATE INDEX IF NOT EXISTS idx_customer_vendor_links_relationship_type ON customer_vendor_links(relationship_type); CREATE OR REPLACE FUNCTION update_customer_vendor_links_updated_at() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = CURRENT_TIMESTAMP; RETURN NEW; END; $$ LANGUAGE plpgsql; DROP TRIGGER IF EXISTS trg_customer_vendor_links_updated_at ON customer_vendor_links; CREATE TRIGGER trg_customer_vendor_links_updated_at BEFORE UPDATE ON customer_vendor_links FOR EACH ROW EXECUTE FUNCTION update_customer_vendor_links_updated_at(); -- Backfill links by CVR first (most reliable) INSERT INTO customer_vendor_links (customer_id, vendor_id, relationship_type) SELECT c.id, v.id, 'supplier' FROM customers c JOIN vendors v ON regexp_replace(COALESCE(c.cvr_number, ''), '\\D', '', 'g') <> '' AND regexp_replace(COALESCE(v.cvr_number, ''), '\\D', '', 'g') <> '' AND regexp_replace(COALESCE(c.cvr_number, ''), '\\D', '', 'g') = regexp_replace(COALESCE(v.cvr_number, ''), '\\D', '', 'g') ON CONFLICT (customer_id, vendor_id) DO NOTHING; -- Backfill by exact email match INSERT INTO customer_vendor_links (customer_id, vendor_id, relationship_type) SELECT c.id, v.id, 'supplier' FROM customers c JOIN vendors v ON LOWER(TRIM(COALESCE(c.email, ''))) <> '' AND LOWER(TRIM(COALESCE(v.email, ''))) <> '' AND LOWER(TRIM(COALESCE(c.email, ''))) = LOWER(TRIM(COALESCE(v.email, ''))) ON CONFLICT (customer_id, vendor_id) DO NOTHING; -- Backfill by exact normalized name match INSERT INTO customer_vendor_links (customer_id, vendor_id, relationship_type) SELECT c.id, v.id, 'supplier' FROM customers c JOIN vendors v ON LOWER(TRIM(COALESCE(c.name, ''))) <> '' AND LOWER(TRIM(COALESCE(v.name, ''))) <> '' AND LOWER(TRIM(COALESCE(c.name, ''))) = LOWER(TRIM(COALESCE(v.name, ''))) ON CONFLICT (customer_id, vendor_id) DO NOTHING; COMMENT ON TABLE customer_vendor_links IS 'Links customers to vendors to support entities that are both customer and supplier'; COMMENT ON COLUMN customer_vendor_links.relationship_type IS 'supplier, reseller, or partner';