Files
botino/db/migrations/20260501130000_seed_piaf_settings_and_replies.sql
Lucas Tettamanti c93955fa55 Limpiar legacy delivery_* + arreglar carga del mapa en shadow DOM
Backend cleanup (todo el delivery vive ahora en delivery_zones.zones[]):
- Migration drop columns delivery_enabled / delivery_days / delivery_hours_start /
  delivery_hours_end / delivery_min_order y limpieza de schedule.delivery JSONB.
- settingsRepo: SELECT/INSERT/UPDATE sólo con campos vigentes, formatScheduleHours
  trabaja sobre pickup.
- handlers/settings: defaults sin legacy, validateSchedule sólo para pickup,
  validateDeliveryZones nuevo (estructura GeoJSON + días).
- seed_piaf_settings_and_replies + tenant_settings migrations alineadas: schedule
  sólo tiene pickup, delivery_zones queda en {} para reconfigurar via UI.

Frontend cleanup:
- settings-crud: borrado el panel "Delivery (Envío a domicilio)" + minOrder,
  toggle deliveryEnabled, y el grid schedule.delivery. collectScheduleFromInputs
  ahora sólo procesa pickup. save() ya no envía delivery_enabled/min_order.

Fix mapa (no cargaba):
- zone-map-editor: los <link> a leaflet.css/leaflet-geoman.css se inyectaban en
  document.head, que NO cruza el shadow DOM de settings-crud, por lo que las
  reglas de Leaflet no aplicaban al div del mapa. Ahora los <link> se anclan
  como hijos del propio web component; al estar en light DOM dentro del shadow
  root del padre, sí aplican.
- Espera explícita a que el stylesheet cargue antes de instanciar L.map.
- ResizeObserver + invalidateSize() para cuando el contenedor cambia tamaño
  (router muestra/oculta panel, tabs, etc).

Smoke E2E sin regresión: 1kg vacío + envío → location en Centro → "martes 12hs"
→ orden confirmada con $28.000 (producto + envío). 157/157 tests verde.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 15:37:47 -03:00

89 lines
5.1 KiB
SQL

-- migrate:up
-- Seed mono-tenant: settings de tienda (horarios + zonas de delivery) +
-- reply_templates con todas las variantes hoy hardcodeadas en DEFAULTS.
-- Esto desbloquea editar respuestas vía UI/SQL sin redeploy.
-- 1) tenant_settings: schedule + delivery_zones para piaf
UPDATE tenant_settings
SET
store_name = COALESCE(NULLIF(store_name, 'Mi Negocio'), 'Piaf'),
bot_name = COALESCE(NULLIF(bot_name, 'Bot'), 'Piaf'),
pickup_enabled = true,
schedule = '{
"pickup": {
"lun": {"enabled": true, "start": "09:00", "end": "20:00"},
"mar": {"enabled": true, "start": "09:00", "end": "20:00"},
"mie": {"enabled": true, "start": "09:00", "end": "20:00"},
"jue": {"enabled": true, "start": "09:00", "end": "20:00"},
"vie": {"enabled": true, "start": "09:00", "end": "20:00"},
"sab": {"enabled": true, "start": "09:00", "end": "13:00"}
}
}'::jsonb,
delivery_zones = '{}'::jsonb
WHERE tenant_id = 'eb71b9a7-9ccf-430e-9b25-951a0c589c0f'::uuid;
-- 2) reply_templates: seed con DEFAULTS de replyTemplates.js para piaf
INSERT INTO reply_templates (tenant_id, template_key, variant, content, weight)
SELECT
'eb71b9a7-9ccf-430e-9b25-951a0c589c0f'::uuid,
v.template_key,
v.variant,
v.content,
v.weight
FROM (VALUES
-- IDLE
('idle.greeting', 1, '¡Hola! ¿En qué te puedo ayudar?', 1),
('idle.greeting', 2, '¡Hola! Estoy para ayudarte con tu pedido. ¿Qué andás buscando?', 1),
('idle.greeting', 3, 'Buenas. ¿Querés que te muestre algo en particular o hacemos un pedido?', 1),
('idle.help_prompt', 1, 'Decime qué necesitás. Podés pedirme productos, precios, o armar el pedido directo.', 1),
('idle.help_prompt', 2, '¿Qué te tiro? Podés pedir algo, preguntar precios o consultar disponibilidad.', 1),
-- CART
('cart.ask_more', 1, '¿Algo más?', 1),
('cart.ask_more', 2, '¿Querés agregar algo más al pedido?', 1),
('cart.ask_more', 3, '¿Sumamos algo más o cerramos así?', 1),
('cart.empty_prompt', 1, 'Tu carrito está vacío. ¿Qué querés agregar?', 1),
('cart.empty_prompt', 2, 'Todavía no hay nada en el carrito. ¿Por dónde empezamos?', 1),
('cart.not_found', 1, 'No encontré "{{query}}". ¿Podés decirlo de otra forma?', 1),
('cart.not_found', 2, 'Mmm, no tengo "{{query}}" exacto. ¿Probamos con otra cosa?', 1),
('cart.not_found', 3, 'No me aparece "{{query}}". Si querés, dame otro nombre o detalle más.', 1),
('cart.didnt_understand', 1, 'Perdón, no te entendí.', 1),
('cart.didnt_understand', 2, 'No me quedó claro, ¿me lo decís de otra forma?', 1),
('cart.didnt_understand', 3, 'No te seguí, ¿podés repetir?', 1),
('cart.skip_acknowledged', 1, 'Ok, lo dejamos.', 1),
('cart.skip_acknowledged', 2, 'Listo, no lo agregamos.', 1),
('cart.confirm_to_shipping', 1, 'Buenísimo. ¿Es para delivery o lo pasás a buscar?', 1),
('cart.confirm_to_shipping', 2, 'Perfecto. ¿Te lo enviamos o lo retirás?', 1),
('cart.pending_before_close', 1, 'Antes de cerrar, ¿qué hacemos con lo que quedó pendiente?', 1),
('cart.pending_before_close', 2, 'Tenemos algo pendiente para resolver antes de cerrar el pedido.', 1),
('cart.added_confirm', 1, 'Anoté {{summary}}. ¿Algo más?', 1),
('cart.added_confirm', 2, 'Listo, {{summary}} agregado. ¿Sumamos algo más?', 1),
('cart.added_confirm', 3, 'Sumé {{summary}}. ¿Querés agregar algo más?', 1),
('cart.added_confirm', 4, 'Va {{summary}}. ¿Algo más?', 1),
('cart.ask_what_product', 1, '¿Qué producto querés?', 1),
('cart.ask_what_product', 2, 'Decime el producto y lo busco.', 1),
('cart.price_no_query', 1, '¿De qué producto querés saber el precio?', 1),
('cart.price_no_query', 2, 'Decime el producto y te paso el precio.', 1),
('cart.price_results_header', 1, 'Estos son los precios:', 1),
('cart.price_results_header', 2, 'Precios disponibles:', 1),
-- SHIPPING (incluye {{delivery_zones_summary}} y {{delivery_hours}} cuando hay datos)
('shipping.ask_method', 1, '¿Lo enviamos a domicilio o lo pasás a buscar?', 1),
('shipping.ask_method', 2, '¿Es para delivery o pickup?', 1),
('shipping.ask_address', 1, 'Pasame la dirección de entrega.', 1),
('shipping.ask_address', 2, 'Decime dónde lo entregamos (calle y altura). Hacemos delivery en {{delivery_zones_summary}}.', 1),
('shipping.address_recorded', 1, 'Anotado: {{address}}.', 1),
('shipping.address_recorded', 2, 'Listo, dirección guardada: {{address}}.', 1),
-- ORDER CLOSE
('order.confirmed', 1, '¡Listo! Anotamos tu pedido. Te coordinamos por acá la entrega.', 1),
('order.confirmed', 2, 'Perfecto, ya quedó registrado. Te confirmamos en breve los detalles de entrega.', 1),
('order.confirmed', 3, 'Genial, anotado. Cualquier ajuste avisame por acá.', 1)
) AS v(template_key, variant, content, weight)
ON CONFLICT (tenant_id, template_key, variant) DO NOTHING;
-- migrate:down
DELETE FROM reply_templates
WHERE tenant_id = 'eb71b9a7-9ccf-430e-9b25-951a0c589c0f'::uuid;
-- Settings: limpiar schedule/zones (no borrar la fila)
UPDATE tenant_settings
SET schedule = '{}'::jsonb, delivery_zones = '{}'::jsonb
WHERE tenant_id = 'eb71b9a7-9ccf-430e-9b25-951a0c589c0f'::uuid;