- Register all missing migrations in runner.py - Make v4.3 idempotent (rename xml_unsigned only if exists) - Make v3.3 idempotent (skip warehouse_inventory/purchase_order_items ops when tables/columns missing) - Mark v3.3.1 and v3.9 as master-only (SKIP) - Mark v3.5.1 as optional (skip if whatsapp tables missing) - Runner skips files marked with '-- : SKIP'
119 lines
5.5 KiB
PL/PgSQL
119 lines
5.5 KiB
PL/PgSQL
-- : SKIP
|
|
-- ============================================================
|
|
-- v3.5 WhatsApp State Machine
|
|
-- Reorganización del chatbot de AI libre a flujo estructurado
|
|
--
|
|
-- NOTE: This migration requires the WhatsApp tables (whatsapp_sessions,
|
|
-- whatsapp_messages) to be present. Tenant DBs without WhatsApp enabled
|
|
-- should skip this file.
|
|
-- Marked with ': SKIP' so the runner skips it unless WhatsApp is configured.
|
|
-- To apply manually on a tenant with WhatsApp tables:
|
|
-- psql <tenant_db> -f pos/migrations/v3.5_whatsapp_state_machine.sql
|
|
-- (Remove the ': SKIP' line above before manual execution.)
|
|
-- ============================================================
|
|
|
|
DO $$
|
|
BEGIN
|
|
-- 1. Extender whatsapp_sessions con estado y contexto
|
|
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'whatsapp_sessions') THEN
|
|
ALTER TABLE whatsapp_sessions
|
|
ADD COLUMN IF NOT EXISTS state VARCHAR(50) DEFAULT 'idle',
|
|
ADD COLUMN IF NOT EXISTS state_data JSONB DEFAULT '{}',
|
|
ADD COLUMN IF NOT EXISTS customer_id INTEGER REFERENCES customers(id),
|
|
ADD COLUMN IF NOT EXISTS branch_id INTEGER REFERENCES branches(id),
|
|
ADD COLUMN IF NOT EXISTS learning_cycle INTEGER DEFAULT 0,
|
|
ADD COLUMN IF NOT EXISTS created_at TIMESTAMPTZ DEFAULT NOW();
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_wa_sessions_state ON whatsapp_sessions(state);
|
|
CREATE INDEX IF NOT EXISTS idx_wa_sessions_customer ON whatsapp_sessions(customer_id);
|
|
CREATE INDEX IF NOT EXISTS idx_wa_sessions_updated ON whatsapp_sessions(updated_at);
|
|
END IF;
|
|
|
|
-- 2. Tabla de vínculo persistente WA ID ↔ Cliente
|
|
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'customers') THEN
|
|
CREATE TABLE IF NOT EXISTS wa_customer_links (
|
|
phone VARCHAR(50) PRIMARY KEY,
|
|
customer_id INTEGER NOT NULL REFERENCES customers(id),
|
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_wa_cust_link_customer ON wa_customer_links(customer_id);
|
|
|
|
CREATE OR REPLACE FUNCTION update_wa_link_timestamp()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
NEW.updated_at = NOW();
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
DROP TRIGGER IF EXISTS trg_wa_link_updated ON wa_customer_links;
|
|
CREATE TRIGGER trg_wa_link_updated
|
|
BEFORE UPDATE ON wa_customer_links
|
|
FOR EACH ROW EXECUTE FUNCTION update_wa_link_timestamp();
|
|
END IF;
|
|
|
|
-- 3. Tabla de sesiones de aprendizaje (piezas no resueltas)
|
|
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'customers')
|
|
AND EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'inventory')
|
|
AND EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'sales') THEN
|
|
CREATE TABLE IF NOT EXISTS wa_learning_sessions (
|
|
id SERIAL PRIMARY KEY,
|
|
phone VARCHAR(50) NOT NULL,
|
|
customer_id INTEGER REFERENCES customers(id),
|
|
description TEXT NOT NULL,
|
|
offered_parts JSONB DEFAULT '[]',
|
|
status VARCHAR(20) DEFAULT 'pending',
|
|
resolved_part_id INTEGER REFERENCES inventory(id),
|
|
resolution_sale_id INTEGER REFERENCES sales(id),
|
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
resolved_at TIMESTAMPTZ
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_wa_learn_phone ON wa_learning_sessions(phone);
|
|
CREATE INDEX IF NOT EXISTS idx_wa_learn_status ON wa_learning_sessions(status);
|
|
CREATE INDEX IF NOT EXISTS idx_wa_learn_customer ON wa_learning_sessions(customer_id);
|
|
CREATE INDEX IF NOT EXISTS idx_wa_learn_created ON wa_learning_sessions(created_at);
|
|
END IF;
|
|
|
|
-- 4. Tabla de configuración de envío por sucursal
|
|
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'branches') THEN
|
|
CREATE TABLE IF NOT EXISTS branch_delivery_config (
|
|
id SERIAL PRIMARY KEY,
|
|
branch_id INTEGER NOT NULL UNIQUE REFERENCES branches(id),
|
|
is_enabled BOOLEAN DEFAULT FALSE,
|
|
delivery_fee NUMERIC(12,2) DEFAULT 0,
|
|
free_delivery_threshold NUMERIC(12,2) DEFAULT NULL,
|
|
coverage_radius_km INTEGER DEFAULT NULL,
|
|
delivery_hours VARCHAR(100) DEFAULT 'Lun-Vie 9:00-18:00',
|
|
notes TEXT,
|
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
END IF;
|
|
|
|
-- 5. Agregar push_name a whatsapp_messages
|
|
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'whatsapp_messages') THEN
|
|
ALTER TABLE whatsapp_messages
|
|
ADD COLUMN IF NOT EXISTS push_name VARCHAR(200);
|
|
END IF;
|
|
|
|
-- 6. Migrar datos existentes
|
|
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'whatsapp_sessions')
|
|
AND EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'wa_customer_links')
|
|
AND EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'customers') THEN
|
|
INSERT INTO wa_customer_links (phone, customer_id)
|
|
SELECT ws.phone, c.id
|
|
FROM whatsapp_sessions ws
|
|
JOIN customers c ON c.phone = ws.phone
|
|
WHERE ws.phone IS NOT NULL AND c.phone IS NOT NULL
|
|
ON CONFLICT (phone) DO NOTHING;
|
|
|
|
UPDATE whatsapp_sessions ws
|
|
SET customer_id = wcl.customer_id
|
|
FROM wa_customer_links wcl
|
|
WHERE ws.phone = wcl.phone AND ws.customer_id IS NULL;
|
|
END IF;
|
|
END $$;
|