-- v2.7 Automatic Notifications Engine -- Notification templates per tenant CREATE TABLE IF NOT EXISTS notification_templates ( id SERIAL PRIMARY KEY, tenant_id INTEGER NOT NULL, event_type VARCHAR(50) NOT NULL, -- 'low_stock', 'order_ready', 'maintenance_due', 'new_sale', 'po_received', 'reorder_alert', 'warranty_expiring' channel VARCHAR(20) NOT NULL DEFAULT 'push', -- 'push', 'email', 'whatsapp', 'sms', 'in_app' name VARCHAR(200) NOT NULL, subject_template VARCHAR(500), body_template TEXT NOT NULL, is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW(), UNIQUE(tenant_id, event_type, channel) ); -- Notification delivery log CREATE TABLE IF NOT EXISTS notification_logs ( id SERIAL PRIMARY KEY, tenant_id INTEGER NOT NULL, recipient_type VARCHAR(20) NOT NULL DEFAULT 'employee', -- 'employee', 'customer', 'owner', 'role' recipient_id INTEGER, event_type VARCHAR(50) NOT NULL, channel VARCHAR(20) NOT NULL, subject TEXT, body TEXT, status VARCHAR(20) DEFAULT 'pending', -- pending, sent, delivered, failed, read error_message TEXT, metadata JSONB, -- {sale_id, po_id, inventory_id, etc.} sent_at TIMESTAMPTZ, read_at TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_notif_logs_recipient ON notification_logs(recipient_type, recipient_id, created_at DESC); CREATE INDEX IF NOT EXISTS idx_notif_logs_status ON notification_logs(status) WHERE status IN ('pending', 'failed'); CREATE INDEX IF NOT EXISTS idx_notif_logs_event ON notification_logs(event_type, created_at DESC); -- Notification preferences per employee CREATE TABLE IF NOT EXISTS notification_preferences ( id SERIAL PRIMARY KEY, employee_id INTEGER NOT NULL REFERENCES employees(id) ON DELETE CASCADE, event_type VARCHAR(50) NOT NULL, channel VARCHAR(20) NOT NULL, is_enabled BOOLEAN DEFAULT TRUE, created_at TIMESTAMPTZ DEFAULT NOW(), UNIQUE(employee_id, event_type, channel) ); -- Push subscriptions table (if not already created by push_service) CREATE TABLE IF NOT EXISTS push_subscriptions ( id SERIAL PRIMARY KEY, employee_id INTEGER NOT NULL UNIQUE, subscription_data TEXT NOT NULL, created_at TIMESTAMPTZ DEFAULT NOW() ); -- Default templates INSERT INTO notification_templates (tenant_id, event_type, channel, name, subject_template, body_template) VALUES (1, 'low_stock', 'push', 'Stock Bajo', 'Stock bajo: {part_name}', 'El inventario de {part_name} ({part_number}) tiene solo {stock} unidades. Punto de reorden: {reorder_point}.'), (1, 'order_ready', 'push', 'Orden Lista', 'Orden #{order_number} lista', 'La orden de servicio #{order_number} está lista para entrega. Cliente: {customer_name}.'), (1, 'maintenance_due', 'push', 'Mantenimiento Vencido', 'Mantenimiento vencido', 'El vehículo {vehicle_plate} tiene mantenimiento de {maintenance_type} vencido. Kilometraje: {current_mileage}.'), (1, 'new_sale', 'push', 'Nueva Venta', 'Venta registrada', 'Venta #{sale_id} por ${total} registrada. Método: {payment_method}.'), (1, 'po_received', 'push', 'OC Recibida', 'Orden de compra recibida', 'La orden de compra #{po_id} fue recibida. Total: ${total}.'), (1, 'reorder_alert', 'push', 'Alerta de Reorden', 'Reorden requerida', '{part_name} ({part_number}) está por debajo del punto de reorden. Stock: {stock}, Reorden: {reorder_point}.'), (1, 'warranty_expiring', 'push', 'Garantía por vencer', 'Garantía por vencer', 'La garantía del item {part_name} vence el {expiry_date}. Cliente: {customer_name}.') ON CONFLICT DO NOTHING;