@fayz-ai/plugin-orders 0.22.7 → 0.23.0-canary.20261027164140
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{DeliverySettings-5ACP5XAG.js → DeliverySettings-2KMZ25CI.js} +198 -33
- package/dist/DeliverySettings-2KMZ25CI.js.map +1 -0
- package/dist/chunk-O4W3DNIC.js +174 -0
- package/dist/chunk-O4W3DNIC.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +254 -5
- package/dist/index.js.map +1 -1
- package/dist/lib/delivery-zones.d.ts +67 -0
- package/dist/lib/delivery-zones.d.ts.map +1 -0
- package/dist/lib/onboarding.d.ts +77 -0
- package/dist/lib/onboarding.d.ts.map +1 -0
- package/dist/locales/en.d.ts.map +1 -1
- package/dist/locales/pt-BR.d.ts.map +1 -1
- package/dist/migrations/index.d.ts +2 -0
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/migrations/main.browser.js +3 -1
- package/dist/migrations/main.browser.js.map +1 -1
- package/dist/migrations/main.js +140 -2
- package/dist/migrations/main.js.map +1 -1
- package/dist/settings/DeliverySettings.d.ts.map +1 -1
- package/dist/settings/useDeliverySettings.d.ts +3 -0
- package/dist/settings/useDeliverySettings.d.ts.map +1 -1
- package/package.json +8 -8
- package/dist/DeliverySettings-5ACP5XAG.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/delivery-zones.ts"],"names":[],"mappings":"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","file":"chunk-O4W3DNIC.js","sourcesContent":["// Delivery zones by distance — the pure half of `proposeDeliveryZones`.\n//\n// \"até 3 km R$ 5 em 30 min, 5 km R$ 8 em 40\" is how a house says its policy;\n// `delivery.zones` (migration 007) is how the pool stores it. Everything here\n// is free of React and of the client so the parser can be tested on sentences.\n\nexport interface DeliveryZone {\n /** Upper bound of the band, in km. Bands are sorted ascending by it. */\n maxKm: number\n /** Fee for the band, in the house currency. 0 = free delivery in the band. */\n fee: number\n etaMinutes?: number\n}\n\n/** The row shape under `delivery.zones` — snake_case like every spine setting. */\nexport interface StoredDeliveryZone {\n max_km: number\n fee: number\n eta_minutes?: number | null\n}\n\nconst round2 = (n: number) => Math.round(n * 100) / 100\n\n/** Validates, rounds, sorts by distance and drops duplicates. */\nexport function normalizeZones(input: ReadonlyArray<Partial<DeliveryZone> | null | undefined>): DeliveryZone[] {\n const seen = new Set<number>()\n const out: DeliveryZone[] = []\n for (const raw of input) {\n if (!raw) continue\n const maxKm = Number(raw.maxKm)\n const fee = Number(raw.fee)\n if (!Number.isFinite(maxKm) || maxKm <= 0) continue\n if (!Number.isFinite(fee) || fee < 0) continue\n const eta = raw.etaMinutes === undefined || raw.etaMinutes === null ? undefined : Number(raw.etaMinutes)\n const zone: DeliveryZone = { maxKm: round2(maxKm), fee: round2(fee) }\n if (eta !== undefined && Number.isFinite(eta) && eta > 0) zone.etaMinutes = Math.round(eta)\n out.push(zone)\n }\n out.sort((a, b) => a.maxKm - b.maxKm)\n return out.filter((z) => (seen.has(z.maxKm) ? false : (seen.add(z.maxKm), true)))\n}\n\nexport function zonesFromSetting(value: unknown): DeliveryZone[] {\n if (!Array.isArray(value)) return []\n return normalizeZones(value.map((row) => {\n if (!row || typeof row !== 'object') return null\n const r = row as Record<string, unknown>\n return {\n maxKm: Number(r.max_km ?? r.maxKm),\n fee: Number(r.fee),\n etaMinutes: r.eta_minutes ?? r.etaMinutes ?? undefined,\n } as Partial<DeliveryZone>\n }))\n}\n\nexport function zonesToSetting(zones: ReadonlyArray<DeliveryZone>): StoredDeliveryZone[] {\n return normalizeZones(zones).map((z) => ({\n max_km: z.maxKm,\n fee: z.fee,\n eta_minutes: z.etaMinutes ?? null,\n }))\n}\n\n// ---------------------------------------------------------------------------\n// Parser\n// ---------------------------------------------------------------------------\n\ntype Token =\n | { kind: 'km'; value: number }\n | { kind: 'fee'; value: number }\n | { kind: 'eta'; value: number }\n | { kind: 'num'; value: number }\n\nconst KM = String.raw`(?:km|kms|quil[oô]metros?)`\nconst NUM = String.raw`(\\d+(?:\\.\\d+)?)`\n// Alternatives are tried in this order at every position; the specific forms\n// (\"de 3 a 5 km\", \"entre 3 e 5 km\", \"R$ 5\") come before the bare number.\nconst TOKEN = new RegExp([\n String.raw`(?<rangeA>${NUM})\\s*(?:a|-|–|até)\\s*(?<rangeB>${NUM})\\s*${KM}\\b`,\n String.raw`entre\\s+(?<betweenA>${NUM})\\s+e\\s+(?<betweenB>${NUM})\\s*${KM}\\b`,\n String.raw`r\\$\\s*(?<feeRs>${NUM})`,\n String.raw`(?<unitNum>${NUM})\\s*(?<unit>${KM}|reais|real|contos?|pila|minutos?|mins?|min|horas?|h)\\b`,\n String.raw`(?<free>gr[aá]tis|de gra[cç]a|sem taxa|free)`,\n String.raw`\\bem\\s+(?<emNum>${NUM})\\s*(?<emUnit>horas?|h|minutos?|mins?|min)?\\b(?!\\s*(?:${KM}|reais|real|r\\$))`,\n String.raw`(?<bare>${NUM})`,\n].join('|'), 'gi')\n\nfunction tokenize(text: string): Token[] {\n const s = text.toLowerCase()\n // Decimal comma (\"4,50\") becomes a dot; a comma followed by a space stays a\n // separator (\"5 reais, 6 km\").\n .replace(/(\\d),(\\d)/g, '$1.$2')\n const tokens: Token[] = []\n for (const m of s.matchAll(TOKEN)) {\n const g = m.groups ?? {}\n if (g.rangeB !== undefined) tokens.push({ kind: 'km', value: Number(g.rangeB) })\n else if (g.betweenB !== undefined) tokens.push({ kind: 'km', value: Number(g.betweenB) })\n else if (g.feeRs !== undefined) tokens.push({ kind: 'fee', value: Number(g.feeRs) })\n else if (g.unitNum !== undefined) {\n const value = Number(g.unitNum)\n const unit = g.unit ?? ''\n if (/^(km|kms|quil)/.test(unit)) tokens.push({ kind: 'km', value })\n else if (/^(reais|real|conto|pila)/.test(unit)) tokens.push({ kind: 'fee', value })\n else if (/^h/.test(unit)) tokens.push({ kind: 'eta', value: value * 60 })\n else tokens.push({ kind: 'eta', value })\n }\n else if (g.free !== undefined) tokens.push({ kind: 'fee', value: 0 })\n else if (g.emNum !== undefined) {\n const hours = /^h/.test(g.emUnit ?? '')\n tokens.push({ kind: 'eta', value: Number(g.emNum) * (hours ? 60 : 1) })\n }\n else if (g.bare !== undefined) tokens.push({ kind: 'num', value: Number(g.bare) })\n }\n return tokens\n}\n\n/**\n * \"até 3 km R$ 5 em 30 min, 5 km R$ 8\" → bands sorted by distance. A band is\n * opened by a distance; the fee and the time that follow belong to it, and a\n * fee said BEFORE its distance (\"R$ 5 até 3 km\") waits for the next one. A\n * band without a fee is dropped; `[]` means nothing was understood.\n */\nexport function parseDeliveryZonesText(text: string): DeliveryZone[] {\n if (!text || !text.trim()) return []\n const zones: Array<Partial<DeliveryZone>> = []\n let current: Partial<DeliveryZone> | null = null\n let pendingFee: number | undefined\n let pendingEta: number | undefined\n\n for (const tok of tokenize(text)) {\n if (tok.kind === 'km') {\n if (current) zones.push(current)\n current = { maxKm: tok.value, fee: pendingFee, etaMinutes: pendingEta }\n pendingFee = undefined\n pendingEta = undefined\n continue\n }\n if (tok.kind === 'fee') {\n if (current && current.fee === undefined) current.fee = tok.value\n else pendingFee = tok.value\n continue\n }\n if (tok.kind === 'eta') {\n if (current && current.etaMinutes === undefined) current.etaMinutes = tok.value\n else if (!current) pendingEta = tok.value\n continue\n }\n // A bare number reads as \"the thing this band still lacks\": first the fee,\n // then the time (\"5 km 8 em 40\" / \"5 km 8 40\").\n if (current) {\n if (current.fee === undefined) current.fee = tok.value\n else if (current.etaMinutes === undefined) current.etaMinutes = tok.value\n } else if (pendingFee === undefined) {\n pendingFee = tok.value\n }\n }\n if (current) zones.push(current)\n return normalizeZones(zones.filter((z) => z.fee !== undefined))\n}\n\n// ---------------------------------------------------------------------------\n// Rendering — what the assistant shows before asking \"posso gravar assim?\"\n// ---------------------------------------------------------------------------\n\nexport function formatFee(fee: number): string {\n if (fee === 0) return 'Grátis'\n return `R$ ${fee.toFixed(2).replace('.', ',')}`\n}\n\nexport function formatKm(km: number): string {\n return `${String(km).replace('.', ',')} km`\n}\n\n/** \"até 3 km\" for the first band, \"3 a 5 km\" for the ones after it. */\nexport function bandLabel(zones: ReadonlyArray<DeliveryZone>, index: number): string {\n const zone = zones[index]\n if (index === 0) return `até ${formatKm(zone.maxKm)}`\n return `${String(zones[index - 1].maxKm).replace('.', ',')} a ${formatKm(zone.maxKm)}`\n}\n\n/** Markdown table — the chat renders it; the settings screen has its own list. */\nexport function renderZonesTable(zones: ReadonlyArray<DeliveryZone>): string {\n const sorted = normalizeZones(zones)\n if (sorted.length === 0) return ''\n const lines = ['| Distância | Taxa | Tempo |', '|---|---|---|']\n sorted.forEach((zone, i) => {\n const eta = zone.etaMinutes ? `${zone.etaMinutes} min` : '—'\n lines.push(`| ${bandLabel(sorted, i)} | ${formatFee(zone.fee)} | ${eta} |`)\n })\n return lines.join('\\n')\n}\n\n/** One sentence: \"até 3 km por R$ 5,00, até 5 km por R$ 8,00\". */\nexport function describeZones(zones: ReadonlyArray<DeliveryZone>): string {\n return normalizeZones(zones).map((z) => `até ${formatKm(z.maxKm)} por ${formatFee(z.fee)}`).join(', ')\n}\n\n/** A band the person can read: \"até 3 km · R$ 5,00 · 30 min\". */\nexport type LabelledDeliveryZone = DeliveryZone & { label: string }\n\n/**\n * Each band with its own line. The confirmation card lists array items by\n * their `label`, so this is what makes \"Item 1 · Item 2\" read as bands.\n */\nexport function labelZones(zones: ReadonlyArray<DeliveryZone>): LabelledDeliveryZone[] {\n const sorted = normalizeZones(zones)\n return sorted.map((z, i) => ({\n ...z,\n label: [bandLabel(sorted, i), formatFee(z.fee), z.etaMinutes ? `${z.etaMinutes} min` : null].filter(Boolean).join(' · '),\n }))\n}\n\n/** Band by band with its time: \"até 3 km · R$ 5,00 · 30 min; 3 a 5 km · R$ 8,00 · 40 min\". */\nexport function summarizeZones(zones: ReadonlyArray<DeliveryZone>): string {\n return labelZones(zones).map((z) => z.label).join('; ')\n}\n\n/** \"R$ 5\" when the fee is whole, \"R$ 5,50\" when it is not, \"grátis\" when it is nothing. */\nfunction shortFee(fee: number): string {\n if (fee === 0) return 'grátis'\n return Number.isInteger(fee) ? `R$ ${fee}` : formatFee(fee)\n}\n\n/**\n * The same bands in the fewest words — \"até 3 km R$ 5 (30 min); 3 a 5 km\n * R$ 8 (40 min)\" — for the confirmation card's RESUMO, which is a single-line\n * field: the long form with \"·\" and \",00\" was cut mid-band at three bands.\n * Every band is there, whole; the table is the place for columns.\n */\nexport function summarizeZonesShort(zones: ReadonlyArray<DeliveryZone>): string {\n const sorted = normalizeZones(zones)\n return sorted\n .map((z, i) => `${bandLabel(sorted, i)} ${shortFee(z.fee)}${z.etaMinutes ? ` (${z.etaMinutes} min)` : ''}`)\n .join('; ')\n}\n\n// ---------------------------------------------------------------------------\n// Errors — what the spine says when a write is refused, in the house's words.\n// Shared by the assistant's tool and the Configurações › Entrega screen, so\n// the same refusal reads the same in both places.\n// ---------------------------------------------------------------------------\n\n/** The plugin-orders migration that registers `delivery.zones`. */\nexport const DELIVERY_ZONES_MIGRATION = '007_delivery_has_zones'\n\nexport const DELIVERY_ZONES_MIGRATION_MESSAGE =\n `A chave delivery.zones ainda não existe no servidor — a migration 007 (${DELIVERY_ZONES_MIGRATION}, plugin-orders) precisa ser aplicada no banco.`\n\nexport const SETTINGS_FORBIDDEN_MESSAGE = 'Só quem gerencia as configurações pode gravar a entrega.'\n\nexport type SettingWriteFailure = 'migration_missing' | 'forbidden' | 'error'\n\nexport function errorCode(e: unknown): string | undefined {\n return typeof e === 'object' && e && 'code' in e ? String((e as { code: unknown }).code) : undefined\n}\n\nexport function errorMessage(e: unknown): string {\n if (e instanceof Error) return e.message\n if (typeof e === 'object' && e && 'message' in e) return String((e as { message: unknown }).message)\n return String(e)\n}\n\n/**\n * `tenant_setting_set` refuses an unregistered key with \"unknown key <k>\"\n * (ERRCODE 22023) and a missing `settings.manage` with 42501. Both used to\n * surface as \"não conseguimos gravar devido a um erro\"; now they name the cause.\n */\nexport function classifySettingWriteError(e: unknown): { reason: SettingWriteFailure; message: string } {\n const raw = errorMessage(e)\n const unknownKey = /unknown key\\s+(\\S+)/i.exec(raw)\n if (unknownKey) {\n const key = unknownKey[1]\n return {\n reason: 'migration_missing',\n message: key === 'delivery.zones'\n ? DELIVERY_ZONES_MIGRATION_MESSAGE\n : `A chave ${key} ainda não existe no servidor — a migration que a registra precisa ser aplicada no banco.`,\n }\n }\n if (errorCode(e) === '42501' || /settings\\.manage/i.test(raw)) return { reason: 'forbidden', message: SETTINGS_FORBIDDEN_MESSAGE }\n return { reason: 'error', message: raw }\n}\n"]}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC5E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAClD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAA;AACvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAA;AAanE,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAwB,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
+
import { summarizeZonesShort, renderZonesTable, labelZones, zonesToSetting, classifySettingWriteError, describeZones, zonesFromSetting, normalizeZones, parseDeliveryZonesText } from './chunk-O4W3DNIC.js';
|
|
1
2
|
export { ORDER_DETAIL_COMPONENT_ID } from './chunk-YVC7R552.js';
|
|
2
3
|
import React2 from 'react';
|
|
3
|
-
import { createConnectionStore, connectionRuns, connectionSettings, connectionStatus, settingsStatus, tl, lazyComponent, useTranslation, getSupabaseClientOptional, getActiveTenantId, getActiveUnitId } from '@fayz-ai/core';
|
|
4
|
+
import { createConnectionStore, connectionRuns, connectionSettings, connectionStatus, settingsStatus, tl, lazyComponent, useTranslation, getSupabaseClientOptional, getActiveTenantId, getActiveUnitId, emitDomainEvent } from '@fayz-ai/core';
|
|
4
5
|
import { createSupabaseOrdersProvider } from '@fayz-ai/orders/data/supabase';
|
|
5
6
|
export { createSupabaseOrdersProvider as createCoreOrdersProvider } from '@fayz-ai/orders/data/supabase';
|
|
6
7
|
import { createOrdersStore } from '@fayz-ai/orders/store';
|
|
7
8
|
import { MIGRATIONS } from '#migrations/main';
|
|
8
9
|
import { RefreshCw, Play, Pause, Loader2, Trash2, Plus, Save, Image, Pencil, Link2, Unlink, X } from 'lucide-react';
|
|
9
10
|
import { Button, Input } from '@fayz-ai/ui';
|
|
10
|
-
import { fayzConnectorOAuth, defineSettingsTab, PluginSettingsPanel, serviceBaseUrl } from '@fayz-ai/admin';
|
|
11
|
+
import { fayzConnectorOAuth, defineSettingsTab, PluginSettingsPanel, serviceBaseUrl, registerAIToolHandler } from '@fayz-ai/admin';
|
|
11
12
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
12
13
|
export { ADVANCE_VERB, DEFAULT_STATUS_CONFIGS, KANBAN_COLUMNS, STATUS_FLOW, getNextStatus, getPreviousStatus, mapToKanbanColumn } from '@fayz-ai/orders/domain/order';
|
|
13
14
|
export { createFayzOrdersProvider } from '@fayz-ai/orders/data/platform';
|
|
@@ -279,7 +280,25 @@ var en = {
|
|
|
279
280
|
"orders.ifoodStore.error.categoryRequired": "Choose the product's category.",
|
|
280
281
|
"orders.ifoodStore.error.badImage": "iFood takes PNG or JPEG photos. Send the photo in one of those formats.",
|
|
281
282
|
"orders.ifoodStore.error.imageTooBig": "The photo is larger than 3.9 MB, iFood's limit. Send a smaller photo.",
|
|
282
|
-
"orders.ifoodStore.error.generic": "The action could not be completed."
|
|
283
|
+
"orders.ifoodStore.error.generic": "The action could not be completed.",
|
|
284
|
+
// Delivery bands by distance (Settings › Delivery)
|
|
285
|
+
"orders.zones.title": "Bands by distance",
|
|
286
|
+
"orders.zones.description": "Fee and time per kilometre from the house. Empty = the single fee above applies to everyone.",
|
|
287
|
+
"orders.zones.empty": "No bands. The delivery fee above applies at any distance.",
|
|
288
|
+
"orders.zones.upTo": "up to",
|
|
289
|
+
"orders.zones.km": "km",
|
|
290
|
+
"orders.zones.fee": "Fee",
|
|
291
|
+
"orders.zones.eta": "min",
|
|
292
|
+
"orders.zones.add": "Add band",
|
|
293
|
+
"orders.zones.remove": "Remove band up to {{km}} km",
|
|
294
|
+
"orders.zones.invalid": "Use numbers, like 3 and 5.90.",
|
|
295
|
+
"orders.zones.radius": "Delivery radius: {{km}} km (the largest band).",
|
|
296
|
+
// Delivery by conversation: the confirmation card and the screen's warning
|
|
297
|
+
"orders.delivery.saveFailed": "Could not save delivery",
|
|
298
|
+
"chat.tool.proposeDeliveryZones": "Propose delivery bands",
|
|
299
|
+
"chat.tool.saveDeliveryZones": "Save delivery bands",
|
|
300
|
+
"chat.field.saveDeliveryZones.zones": "Bands",
|
|
301
|
+
"chat.field.saveDeliveryZones.summary": "Summary"
|
|
283
302
|
};
|
|
284
303
|
|
|
285
304
|
// src/locales/pt-BR.ts
|
|
@@ -518,7 +537,25 @@ var ptBR = {
|
|
|
518
537
|
"orders.ifoodStore.error.categoryRequired": "Escolha a categoria do produto.",
|
|
519
538
|
"orders.ifoodStore.error.badImage": "O iFood aceita fotos PNG ou JPEG. Envie a foto em um desses formatos.",
|
|
520
539
|
"orders.ifoodStore.error.imageTooBig": "A foto passa de 3,9 MB, o limite do iFood. Envie uma foto menor.",
|
|
521
|
-
"orders.ifoodStore.error.generic": "N\xE3o foi poss\xEDvel concluir a a\xE7\xE3o."
|
|
540
|
+
"orders.ifoodStore.error.generic": "N\xE3o foi poss\xEDvel concluir a a\xE7\xE3o.",
|
|
541
|
+
// Faixas de entrega por distância (Configurações › Delivery)
|
|
542
|
+
"orders.zones.title": "Faixas por dist\xE2ncia",
|
|
543
|
+
"orders.zones.description": "Taxa e tempo por quil\xF4metro a partir da casa. Vazio = a taxa \xFAnica acima vale para todo mundo.",
|
|
544
|
+
"orders.zones.empty": "Nenhuma faixa. A taxa de entrega acima vale para qualquer dist\xE2ncia.",
|
|
545
|
+
"orders.zones.upTo": "at\xE9",
|
|
546
|
+
"orders.zones.km": "km",
|
|
547
|
+
"orders.zones.fee": "Taxa",
|
|
548
|
+
"orders.zones.eta": "min",
|
|
549
|
+
"orders.zones.add": "Adicionar faixa",
|
|
550
|
+
"orders.zones.remove": "Remover faixa at\xE9 {{km}} km",
|
|
551
|
+
"orders.zones.invalid": "Use n\xFAmeros, como 3 e 5,90.",
|
|
552
|
+
"orders.zones.radius": "Raio de entrega: {{km}} km (a maior faixa).",
|
|
553
|
+
// Entrega por conversa: o card de confirmação e o aviso da tela
|
|
554
|
+
"orders.delivery.saveFailed": "N\xE3o foi poss\xEDvel salvar a entrega",
|
|
555
|
+
"chat.tool.proposeDeliveryZones": "Montar faixas de entrega",
|
|
556
|
+
"chat.tool.saveDeliveryZones": "Gravar faixas de entrega",
|
|
557
|
+
"chat.field.saveDeliveryZones.zones": "Faixas",
|
|
558
|
+
"chat.field.saveDeliveryZones.summary": "Resumo"
|
|
522
559
|
};
|
|
523
560
|
|
|
524
561
|
// src/locales/index.ts
|
|
@@ -2516,7 +2553,142 @@ var ordersV1SettingsTabs = [
|
|
|
2516
2553
|
]
|
|
2517
2554
|
})
|
|
2518
2555
|
];
|
|
2519
|
-
var
|
|
2556
|
+
var SERVICE_MODES_ANSWER = "food.serviceModes";
|
|
2557
|
+
var OWN_DELIVERY_MODE = "own-delivery";
|
|
2558
|
+
var DELIVERY_ZONES_SAVED_EVENT = "orders.delivery_zones_saved";
|
|
2559
|
+
var PROPOSE_DELIVERY_ZONES_TOOL = "proposeDeliveryZones";
|
|
2560
|
+
var SAVE_DELIVERY_ZONES_TOOL = "saveDeliveryZones";
|
|
2561
|
+
var DELIVERY_ROUTING_RULE = 'Qualquer frase sobre entrega/delivery/taxa de entrega/frete/raio com km, R$ ou minutos ("at\xE9 3 km R$ 5 em 30 min, 5 km por R$ 8 em 40 min", "configurar entrega", "cobro 6 reais at\xE9 4 km") \xE9 proposeDeliveryZones. NUNCA \xE9 conta a pagar, despesa, fornecedor ou financeiro: "entrega" aqui n\xE3o \xE9 um fornecedor e esses R$ s\xE3o a taxa cobrada do cliente.';
|
|
2562
|
+
var NOT_UNDERSTOOD_HINT = "N\xE3o consegui montar as faixas com isso. Pe\xE7a assim: at\xE9 3 km R$ 5 em 30 min; at\xE9 5 km R$ 8 em 40 min.";
|
|
2563
|
+
var MISSING_ETA_HINT = "Entendi as dist\xE2ncias, mas n\xE3o o tempo de todas as faixas. Pergunte s\xF3 o que faltou e mantenha o resto.";
|
|
2564
|
+
function client() {
|
|
2565
|
+
return getSupabaseClientOptional();
|
|
2566
|
+
}
|
|
2567
|
+
async function deliveryConfigured() {
|
|
2568
|
+
const db2 = client();
|
|
2569
|
+
if (!db2) return false;
|
|
2570
|
+
const { data, error } = await db2.rpc("tenant_settings");
|
|
2571
|
+
if (error || !data || typeof data !== "object") return false;
|
|
2572
|
+
const flat = data;
|
|
2573
|
+
if (zonesFromSetting(flat["delivery.zones"]).length > 0) return true;
|
|
2574
|
+
const fee = Number(flat["delivery.fee"]);
|
|
2575
|
+
return Number.isFinite(fee) && fee > 0;
|
|
2576
|
+
}
|
|
2577
|
+
function zonesFromArgs(args) {
|
|
2578
|
+
const structured = Array.isArray(args.zones) ? normalizeZones(args.zones) : [];
|
|
2579
|
+
return structured.length > 0 ? structured : parseDeliveryZonesText(String(args.text ?? ""));
|
|
2580
|
+
}
|
|
2581
|
+
function proposeDeliveryZones(args) {
|
|
2582
|
+
const zones = zonesFromArgs(args);
|
|
2583
|
+
if (zones.length === 0) return { ok: false, reason: "not_understood", hint: NOT_UNDERSTOOD_HINT };
|
|
2584
|
+
const missingEta = zones.some((z) => !z.etaMinutes);
|
|
2585
|
+
const summary = summarizeZonesShort(zones);
|
|
2586
|
+
return {
|
|
2587
|
+
ok: true,
|
|
2588
|
+
saved: false,
|
|
2589
|
+
proposal: labelZones(zones),
|
|
2590
|
+
card: renderZonesTable(zones),
|
|
2591
|
+
summary,
|
|
2592
|
+
missingEta,
|
|
2593
|
+
...missingEta ? { hint: MISSING_ETA_HINT } : {},
|
|
2594
|
+
next: missingEta ? `Nada foi gravado. Comece o texto da sua resposta pela tabela de card, copiada tal qual (\xE9 markdown), e pergunte s\xF3 o que faltou (tempo ou valor), mantendo o resto; depois proponha de novo.` : `Nada foi gravado. Sua resposta em texto DEVE come\xE7ar pela tabela de card, copiada tal qual (\xE9 markdown; n\xE3o a resuma nem a descreva) \u2014 a pessoa precisa ler as faixas antes do card de confirma\xE7\xE3o. Em seguida, NESTA MESMA resposta, chame ${SAVE_DELIVERY_ZONES_TOOL} com estas mesmas faixas em zones (com label e etaMinutes) e este summary. O card nativo dessa ferramenta \xE9 onde a pessoa confirma ou cancela \u2014 n\xE3o pergunte "posso gravar?" em texto, a pergunta \xE9 o card. Se ela cancelar, pergunte o que ajustar.`
|
|
2595
|
+
};
|
|
2596
|
+
}
|
|
2597
|
+
async function saveDeliveryZones(args) {
|
|
2598
|
+
const zones = zonesFromArgs(args);
|
|
2599
|
+
if (zones.length === 0) {
|
|
2600
|
+
return { ok: false, reason: "not_understood", message: "Nenhuma faixa para gravar.", hint: NOT_UNDERSTOOD_HINT };
|
|
2601
|
+
}
|
|
2602
|
+
const db2 = client();
|
|
2603
|
+
if (!db2) return { ok: false, reason: "unsupported", message: "Este app n\xE3o guarda a configura\xE7\xE3o de entrega." };
|
|
2604
|
+
const writes = [
|
|
2605
|
+
["delivery.zones", zonesToSetting(zones)],
|
|
2606
|
+
["delivery.enabled", true],
|
|
2607
|
+
["delivery.radius_km", zones[zones.length - 1].maxKm]
|
|
2608
|
+
];
|
|
2609
|
+
const firstEta = zones[0].etaMinutes;
|
|
2610
|
+
if (firstEta) writes.push(["delivery.eta_minutes", firstEta]);
|
|
2611
|
+
try {
|
|
2612
|
+
for (const [key, value] of writes) {
|
|
2613
|
+
const { error } = await db2.rpc("tenant_setting_set", { p_key: key, p_value: value });
|
|
2614
|
+
if (error) throw error;
|
|
2615
|
+
}
|
|
2616
|
+
} catch (e) {
|
|
2617
|
+
const failure = classifySettingWriteError(e);
|
|
2618
|
+
return {
|
|
2619
|
+
ok: false,
|
|
2620
|
+
...failure,
|
|
2621
|
+
hint: failure.reason === "migration_missing" ? "Diga \xE0 pessoa, com estas palavras, que a migration 007 ainda n\xE3o foi aplicada no banco e que as faixas podem ser gravadas assim que ela estiver no ar. N\xE3o tente de novo agora." : void 0
|
|
2622
|
+
};
|
|
2623
|
+
}
|
|
2624
|
+
emitDomainEvent(DELIVERY_ZONES_SAVED_EVENT, { zones: zones.length }, { tenantId: getActiveTenantId() ?? null });
|
|
2625
|
+
return { ok: true, saved: true, zones, card: renderZonesTable(zones), summary: describeZones(zones) };
|
|
2626
|
+
}
|
|
2627
|
+
function registerDeliveryZonesHandler() {
|
|
2628
|
+
registerAIToolHandler(PROPOSE_DELIVERY_ZONES_TOOL, (args) => proposeDeliveryZones(args));
|
|
2629
|
+
registerAIToolHandler(SAVE_DELIVERY_ZONES_TOOL, (args) => saveDeliveryZones(args));
|
|
2630
|
+
}
|
|
2631
|
+
function buildOrdersOnboarding() {
|
|
2632
|
+
return {
|
|
2633
|
+
id: "orders",
|
|
2634
|
+
title: tl("Your orders", "Seus pedidos"),
|
|
2635
|
+
order: 20,
|
|
2636
|
+
instructions: tl(
|
|
2637
|
+
`You are setting up delivery. ROUTING: any sentence about delivery/delivery fee/radius with km, R$ or minutes ("at\xE9 3 km R$ 5 em 30 min, 5 km por R$ 8 em 40 min", "configurar entrega") goes to ${PROPOSE_DELIVERY_ZONES_TOOL} \u2014 never to payables, expenses, suppliers or anything financial; "entrega" is not a supplier and those R$ are what the customer pays.
|
|
2638
|
+
- Call ${PROPOSE_DELIVERY_ZONES_TOOL} with the text EXACTLY as typed (never rewrite it: "em 40 min" is a time). It never writes and asks nothing: it returns the table and the labelled bands.
|
|
2639
|
+
- Start your reply's text with the table (the card field, verbatim markdown) and, in the SAME reply, call ${SAVE_DELIVERY_ZONES_TOOL} with those bands (zones with label and etaMinutes) and the summary. Its native confirmation card is the ONE place the person approves or cancels \u2014 never ask "can I save?" in text, and never confirm twice.
|
|
2640
|
+
- If a band is missing its time or fee, ask only for what is missing and keep the rest; propose again before saving.
|
|
2641
|
+
- If saving fails because the key does not exist yet (migration 007), say exactly that and do not retry. If the person cancels the card, ask what to change.
|
|
2642
|
+
- A house that charges by neighbourhood: ask for the neighbourhoods and the fee of each, then translate with the person ("how far is the farthest one?") into distance bands; a single fee is one band.
|
|
2643
|
+
- Every step has a guide (readSetupGuide). Read it before leading.`,
|
|
2644
|
+
`Voc\xEA est\xE1 configurando a entrega. ROTEAMENTO: ${DELIVERY_ROUTING_RULE}
|
|
2645
|
+
- Chame ${PROPOSE_DELIVERY_ZONES_TOOL} com o texto EXATAMENTE como veio (nunca reescreva: "em 40 min" \xE9 tempo). Ela nunca grava e n\xE3o pergunta nada: devolve a tabela e as faixas com r\xF3tulo.
|
|
2646
|
+
- Comece o texto da resposta pela tabela (o campo card, markdown copiado tal qual) e, NA MESMA resposta, chame ${SAVE_DELIVERY_ZONES_TOOL} com essas faixas (zones com label e etaMinutes) e o summary. O card nativo de confirma\xE7\xE3o dela \xE9 o \xDANICO lugar em que a pessoa aprova ou cancela \u2014 nunca pergunte "posso gravar?" em texto, nunca confirme duas vezes.
|
|
2647
|
+
- Se faltou o tempo ou o valor de uma faixa, pergunte s\xF3 o que faltou, mantenha o resto e proponha de novo antes de gravar.
|
|
2648
|
+
- Se a grava\xE7\xE3o falhar porque a chave ainda n\xE3o existe (migration 007), diga exatamente isso e n\xE3o tente de novo. Se a pessoa cancelar o card, pergunte o que mudar.
|
|
2649
|
+
- Casa que cobra por bairro: pe\xE7a os bairros e o valor de cada um e traduza com a pessoa ("o mais longe fica a quantos km?") em faixas por dist\xE2ncia; taxa \xFAnica \xE9 uma faixa s\xF3.
|
|
2650
|
+
- Cada passo tem um guia (readSetupGuide). Leia antes de conduzir.`
|
|
2651
|
+
),
|
|
2652
|
+
steps: [
|
|
2653
|
+
{
|
|
2654
|
+
key: "delivery-zones",
|
|
2655
|
+
title: tl("Delivery areas", "\xC1reas de entrega"),
|
|
2656
|
+
description: tl(
|
|
2657
|
+
"How far you deliver and what each band costs \u2014 said in a sentence.",
|
|
2658
|
+
"At\xE9 onde voc\xEA entrega e quanto custa cada faixa \u2014 dito numa frase."
|
|
2659
|
+
),
|
|
2660
|
+
icon: "Bike",
|
|
2661
|
+
route: "/settings/orders-delivery",
|
|
2662
|
+
priority: "high",
|
|
2663
|
+
journey: { group: "launch" },
|
|
2664
|
+
// How the house serves is answered by conversation now (the
|
|
2665
|
+
// getting-started profile step writes the same key the wizard did);
|
|
2666
|
+
// "own delivery" absent from the answer rules the step out, and no
|
|
2667
|
+
// answer yet (older tenant, profile still loading) keeps it.
|
|
2668
|
+
appliesWhen: (answers) => {
|
|
2669
|
+
const modes = answers[SERVICE_MODES_ANSWER];
|
|
2670
|
+
if (!Array.isArray(modes)) return true;
|
|
2671
|
+
return modes.includes(OWN_DELIVERY_MODE);
|
|
2672
|
+
},
|
|
2673
|
+
agentHint: tl(
|
|
2674
|
+
"Ask how the house charges for delivery and wait for the sentence. Any km/R$/min sentence about delivery is proposeDeliveryZones (never a payable): show its table, then call saveDeliveryZones in the same reply \u2014 its native card is the one confirmation.",
|
|
2675
|
+
"Pergunte como a casa cobra a entrega e espere a frase. Toda frase com km/R$/min sobre entrega \xE9 proposeDeliveryZones (nunca conta a pagar): mostre a tabela e chame saveDeliveryZones na mesma resposta \u2014 o card nativo dela \xE9 a \xFAnica confirma\xE7\xE3o."
|
|
2676
|
+
),
|
|
2677
|
+
howTo: tl(
|
|
2678
|
+
'Configura\xE7\xF5es \u203A Delivery. Tell the assistant how you charge ("up to 3 km R$ 5 in 30 min, up to 5 km R$ 8 in 40 min") and confirm the table it shows; or type the bands by hand on the Delivery screen. One fee for everyone is one band.',
|
|
2679
|
+
'Configura\xE7\xF5es \u203A Delivery. Diga \xE0 assistente como voc\xEA cobra ("at\xE9 3 km R$ 5 em 30 min, at\xE9 5 km R$ 8 em 40 min") e confirme a tabela que ela mostrar; ou digite as faixas \xE0 m\xE3o na tela de Delivery. Taxa \xFAnica para todo mundo \xE9 uma faixa s\xF3.'
|
|
2680
|
+
),
|
|
2681
|
+
celebrate: tl("Delivery saved.", "Entrega salva."),
|
|
2682
|
+
script: [
|
|
2683
|
+
{ kind: "say", text: tl("How do you charge for delivery? Send it your way.", "Como voc\xEA cobra a entrega? Pode me mandar do seu jeito.") },
|
|
2684
|
+
{ kind: "await" }
|
|
2685
|
+
],
|
|
2686
|
+
check: deliveryConfigured
|
|
2687
|
+
}
|
|
2688
|
+
]
|
|
2689
|
+
};
|
|
2690
|
+
}
|
|
2691
|
+
var DeliverySettings = lazyComponent(() => import('./DeliverySettings-2KMZ25CI.js').then((m) => m.DeliverySettings));
|
|
2520
2692
|
var OrdersPage = React2.lazy(() => import('./OrdersPage-PMYISO2D.js').then((m) => ({ default: m.OrdersPage })));
|
|
2521
2693
|
var OrderDetailRoute = React2.lazy(() => import('./OrderDetailRoute-HBLR4UUO.js').then((m) => ({ default: m.OrderDetailRoute })));
|
|
2522
2694
|
var DEFAULT_LABELS = {
|
|
@@ -2557,6 +2729,7 @@ function createOrdersPlugin(options) {
|
|
|
2557
2729
|
onOrderCompleted: config.onOrderCompleted,
|
|
2558
2730
|
onOrderCancelled: config.onOrderCancelled
|
|
2559
2731
|
});
|
|
2732
|
+
registerDeliveryZonesHandler();
|
|
2560
2733
|
const PageComponent = () => React2.createElement(
|
|
2561
2734
|
React2.Suspense,
|
|
2562
2735
|
{ fallback: null },
|
|
@@ -2711,8 +2884,84 @@ function createOrdersPlugin(options) {
|
|
|
2711
2884
|
required: ["kind", "items"]
|
|
2712
2885
|
},
|
|
2713
2886
|
permission: { feature: "orders", action: "create" }
|
|
2887
|
+
},
|
|
2888
|
+
{
|
|
2889
|
+
id: "orders.propose-delivery-zones",
|
|
2890
|
+
name: PROPOSE_DELIVERY_ZONES_TOOL,
|
|
2891
|
+
description: `ENTREGA POR DIST\xC2NCIA (taxa de entrega, delivery, frete, raio, km) \u2014 ${DELIVERY_ROUTING_RULE} FASE 1 de 2: monta as faixas a partir do que a casa escreveu e devolve a tabela e as faixas com r\xF3tulo. NUNCA grava e n\xE3o pergunta nada. Passe o texto EXATAMENTE como a pessoa escreveu em text (n\xE3o reescreva nem resuma: "em 40 min" \xE9 o tempo da faixa); use zones s\xF3 se as faixas j\xE1 vieram estruturadas. Em seguida, na mesma resposta, chame saveDeliveryZones com as faixas devolvidas \u2014 o card nativo dela \xE9 a \xFAnica confirma\xE7\xE3o.`,
|
|
2892
|
+
icon: "Bike",
|
|
2893
|
+
mode: "read",
|
|
2894
|
+
category: "Orders",
|
|
2895
|
+
execution: { plane: "client" },
|
|
2896
|
+
permission: { feature: "settings", action: "read" },
|
|
2897
|
+
parameters: {
|
|
2898
|
+
type: "object",
|
|
2899
|
+
properties: {
|
|
2900
|
+
text: { type: "string", description: 'A frase da casa, sem alterar, ex.: "at\xE9 3 km R$ 5 em 30 min, 5 km por R$ 8 em 40 min".' },
|
|
2901
|
+
zones: {
|
|
2902
|
+
type: "array",
|
|
2903
|
+
description: "Faixas j\xE1 estruturadas, em vez do texto (maxKm, fee e etaMinutes em minutos).",
|
|
2904
|
+
items: {
|
|
2905
|
+
type: "object",
|
|
2906
|
+
properties: {
|
|
2907
|
+
maxKm: { type: "number" },
|
|
2908
|
+
fee: { type: "number" },
|
|
2909
|
+
etaMinutes: { type: "number" },
|
|
2910
|
+
label: { type: "string", description: 'A faixa como a pessoa l\xEA no card ("at\xE9 3 km \xB7 R$ 5,00 \xB7 30 min"), copiada de proposeDeliveryZones.' }
|
|
2911
|
+
},
|
|
2912
|
+
required: ["maxKm", "fee"]
|
|
2913
|
+
}
|
|
2914
|
+
}
|
|
2915
|
+
}
|
|
2916
|
+
},
|
|
2917
|
+
suggestions: [
|
|
2918
|
+
{
|
|
2919
|
+
label: "Configurar entrega por dist\xE2ncia",
|
|
2920
|
+
prompt: "Quero configurar a entrega por dist\xE2ncia (faixas de km, taxa e tempo). Me pergunte como eu cobro."
|
|
2921
|
+
},
|
|
2922
|
+
{
|
|
2923
|
+
label: "Mudar a taxa de entrega",
|
|
2924
|
+
prompt: "Quero mudar a taxa de entrega por dist\xE2ncia. Pergunte como eu cobro hoje e monte as faixas."
|
|
2925
|
+
}
|
|
2926
|
+
]
|
|
2927
|
+
},
|
|
2928
|
+
{
|
|
2929
|
+
id: "orders.save-delivery-zones",
|
|
2930
|
+
name: SAVE_DELIVERY_ZONES_TOOL,
|
|
2931
|
+
description: 'FASE 2 de 2 da entrega por dist\xE2ncia (taxa de entrega \u2014 nunca financeiro). Grava as faixas em delivery.zones e liga a entrega. Abre o card nativo em que a PESSOA confirma ou cancela antes de qualquer grava\xE7\xE3o \u2014 \xE9 a \xDANICA confirma\xE7\xE3o do fluxo. Chame logo depois de proposeDeliveryZones, na mesma resposta, com as mesmas faixas (zones, com label e etaMinutes) e o summary; n\xE3o pergunte "posso gravar?" em texto. Nunca chame por conta pr\xF3pria com faixas que a pessoa n\xE3o disse.',
|
|
2932
|
+
icon: "Bike",
|
|
2933
|
+
mode: "persist",
|
|
2934
|
+
category: "Orders",
|
|
2935
|
+
execution: { plane: "client" },
|
|
2936
|
+
// The person's gate, and the only one: the runtime draws the
|
|
2937
|
+
// ConfirmActionCard with the labelled bands and nothing runs until they
|
|
2938
|
+
// tap. A model that skips phase 1 still cannot skip this.
|
|
2939
|
+
requiresConfirmation: true,
|
|
2940
|
+
permission: { feature: "settings", action: "manage" },
|
|
2941
|
+
parameters: {
|
|
2942
|
+
type: "object",
|
|
2943
|
+
properties: {
|
|
2944
|
+
zones: {
|
|
2945
|
+
type: "array",
|
|
2946
|
+
description: "As faixas confirmadas pela pessoa, em ordem crescente de maxKm.",
|
|
2947
|
+
items: {
|
|
2948
|
+
type: "object",
|
|
2949
|
+
properties: {
|
|
2950
|
+
maxKm: { type: "number" },
|
|
2951
|
+
fee: { type: "number" },
|
|
2952
|
+
etaMinutes: { type: "number" },
|
|
2953
|
+
label: { type: "string", description: 'A faixa como a pessoa l\xEA no card ("at\xE9 3 km \xB7 R$ 5,00 \xB7 30 min"), copiada de proposeDeliveryZones.' }
|
|
2954
|
+
},
|
|
2955
|
+
required: ["maxKm", "fee"]
|
|
2956
|
+
}
|
|
2957
|
+
},
|
|
2958
|
+
summary: { type: "string", description: "O resumo que proposeDeliveryZones devolveu, para a pessoa ler no card." }
|
|
2959
|
+
},
|
|
2960
|
+
required: ["zones"]
|
|
2961
|
+
}
|
|
2714
2962
|
}
|
|
2715
2963
|
],
|
|
2964
|
+
onboarding: { program: buildOrdersOnboarding() },
|
|
2716
2965
|
registries: ordersRegistries,
|
|
2717
2966
|
facets: [
|
|
2718
2967
|
{ id: "scale", label: "Balan\xE7a", description: "Venda por peso com balan\xE7a e etiqueta." },
|