82 lines
3.1 KiB
MySQL
82 lines
3.1 KiB
MySQL
|
|
-- 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';
|