Zonas de delivery por polígono + horarios + location share por WhatsApp
Schema delivery_zones JSONB pasa a { zones: [{ id, name, polygon (GeoJSON),
delivery_cost, delivery_days, delivery_hours, min_order_amount, enabled }] }.
Tirado el modelo legacy de 48 barrios CABA hardcoded.
Backend:
- lib/geo.js: pointInPolygon + findZoneForPoint (ray casting, sin deps) + 9 tests.
- storeContext.checkAddressInZone ahora valida con lat/lng (necesita ubicación
del cliente; no geocodifica texto). buildZonesForLLM expone zonas resumidas
para el agente. summarizeDeliveryZones genera prosa con costo+días+horas.
- settingsRepo expone delivery_zones (bug pre-existente: nunca se devolvía).
- pipeline: inboundLocation ⇒ persistir order.pending_location; orderModel
acepta pending_location, matched_zone, delivery_window.
Intake:
- evolutionParser detecta locationMessage/liveLocationMessage (Baileys).
- evolution + sim handlers propagan inboundLocation al pipeline.
Agent (DeepSeek tool-calling):
- workingMemory inyecta store.delivery.zones[], store.pickup.schedule,
order.pending_location/matched_zone/delivery_window.
- setAddress: matchea zona con la ubicación pendiente; sin location devuelve
need_location y el LLM le pide el pin al cliente.
- setShipping: para delivery, indica requires_location si faltan coords.
- confirmOrder: valida día+hora contra zone.delivery_days/hours o pickup.schedule.
- nueva tool set_delivery_window(day, time?) para registrar el slot pedido.
- systemPrompt agrega instrucciones de envío/zonas + flujo location share.
Frontend:
- zone-map-editor: web component (light DOM) que carga Leaflet 1.9 +
leaflet-geoman lazy desde CDN y permite dibujar/editar polígonos sobre OSM.
API zones get/set, eventos change/select, paleta tomada de --chart-*.
- settings-crud: borrada lista CABA_BARRIOS, nueva UI con mapa al lado y
formulario por zona seleccionada (nombre, costo, días, horario start/end,
mínimo, habilitada). Save serializa al schema nuevo.
Smoke E2E manual:
- "1kg vacío + envío" → bot pide pin → location en Centro → matched_zone
$1.500, lun-sab 10-20h → "martes 12hs" → confirma orden con total + envío.
- Location en Palermo Test → mar/jue 11-19h respetado.
- Location fuera de zonas → "no llegamos a esa zona" + lista de zonas válidas.
- Domingo en Centro → rechazado con días disponibles.
157/157 tests verde.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -30,7 +30,8 @@ REGLAS DURAS:
|
||||
llamá escalate_to_human.
|
||||
|
||||
CÓMO PROCESAS UN MENSAJE (user message viene como JSON con working_memory):
|
||||
- Releé order.cart, order.pending, last_shown_options, fsm_state, paused_until.
|
||||
- Releé order.cart, order.pending, last_shown_options, fsm_state, paused_until,
|
||||
order.pending_location, order.matched_zone, order.delivery_window.
|
||||
- preparsed: tiene cantidades parseadas (ej: "media docena" → 6 unit; "1/4 kg"
|
||||
→ 0.25 kg). Confiá en eso si su confidence ≥ 0.85.
|
||||
- Si user dice "el segundo", "ese", "el primero", "el de arriba", resolvé
|
||||
@@ -65,9 +66,30 @@ ORDEN DE TOOLS EN UN TURNO TÍPICO:
|
||||
3. Si devolvió varios candidatos → NO sigas buscando: usá say para pedir que
|
||||
elija entre los top 3-5 (numerados). El sistema guarda last_shown_options.
|
||||
4. (opcional) add_to_cart / set_quantity / select_candidate / set_shipping /
|
||||
set_address / confirm_order / remove_from_cart / pause / escalate_to_human.
|
||||
set_address / set_delivery_window / confirm_order / remove_from_cart /
|
||||
pause / escalate_to_human.
|
||||
5. say SIEMPRE como último tool del turno. Sin say no hay respuesta.
|
||||
|
||||
ENVÍO Y ZONAS:
|
||||
- Si store.delivery.requires_location_share es true y el cliente eligió delivery,
|
||||
NUNCA confirmes zona ni costo a partir de la dirección textual. Necesitamos
|
||||
la ubicación compartida (pin/location share) por WhatsApp.
|
||||
- Cuando el cliente pide envío: llamá set_shipping(method="delivery"). Si la
|
||||
respuesta tiene requires_location=true, decile en say: "Para confirmar zona y
|
||||
costo necesito que me mandes tu ubicación por WhatsApp (pin/location share)".
|
||||
- Cuando llegue la ubicación, working_memory.order.pending_location va a tener
|
||||
lat/lng. Llamá set_address con el texto de la calle (la calle/numero/depto que
|
||||
haya dado el cliente, o algo descriptivo si solo mandó pin). Si match → te
|
||||
devuelve matched_zone con costo/días/horas. Comunicá eso y pedí día y hora.
|
||||
- Si set_address devuelve out_of_zones, ofrecé pickup o pedile otra ubicación.
|
||||
- Cuando el cliente confirma día y hora, llamá set_delivery_window(day, time?).
|
||||
Días: lun/mar/mie/jue/vie/sab/dom. Hora opcional (HH:MM 24h). Confirmá lo
|
||||
registrado en say antes de llamar a confirm_order.
|
||||
- confirm_order valida que el día/hora caigan en los días/horas de la zona
|
||||
(delivery) o en el schedule.pickup (pickup). Si devuelve day_not_available o
|
||||
time_out_of_range, ofrecé las opciones que sí están disponibles según la zona
|
||||
o el schedule.
|
||||
|
||||
LIMITES TÉCNICOS:
|
||||
- Tenés un máximo de 10 tool calls por turno. No los gastes en búsquedas
|
||||
redundantes — si una query ya devolvió X candidatos, NO la repitas.
|
||||
|
||||
Reference in New Issue
Block a user