n8n-nodes-confirm8 0.22.0 → 0.24.0
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.
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from "n8n-workflow";
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* CONFIRM8 OS TOOL (CHUMBED)
|
|
4
|
+
* - resource is ALWAYS "order"
|
|
5
|
+
* - operation is ALWAYS "getAll" OR "get" (derived only from presence of recordId)
|
|
6
|
+
* - dates are ALWAYS ISO YYYY-MM-DD (validated / computed here)
|
|
7
|
+
*
|
|
8
|
+
* This is the recommended single-tool version to use inside an AI Agent.
|
|
9
|
+
* The agent never sees 'resource' or 'operation' parameters, so it cannot fill them wrong.
|
|
10
|
+
*/
|
|
11
|
+
export declare class Confirm8OSTool implements INodeType {
|
|
3
12
|
description: INodeTypeDescription;
|
|
4
|
-
/**
|
|
5
|
-
* Parse natural date queries into filter JSON
|
|
6
|
-
*/
|
|
7
|
-
private parseDateQuery;
|
|
8
13
|
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
9
14
|
}
|
|
@@ -1,59 +1,29 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"service",
|
|
16
|
-
"product",
|
|
17
|
-
"order",
|
|
18
|
-
"modality",
|
|
19
|
-
"ticket",
|
|
20
|
-
"property",
|
|
21
|
-
];
|
|
22
|
-
const VALID_OPERATIONS = [
|
|
23
|
-
"getAll",
|
|
24
|
-
"get",
|
|
25
|
-
"create",
|
|
26
|
-
"update",
|
|
27
|
-
"activate",
|
|
28
|
-
"deactivate",
|
|
29
|
-
];
|
|
30
|
-
const AGENT_USAGE_NOTE = `
|
|
31
|
-
CRITICAL (Agents):
|
|
32
|
-
- You MUST return ONLY the option *value* token (not the label).
|
|
33
|
-
- Allowed resource values: ${VALID_RESOURCES.join(", ")}
|
|
34
|
-
- Allowed operation values: ${VALID_OPERATIONS.join(", ")}
|
|
35
|
-
Examples:
|
|
36
|
-
- "Ordem de Serviço" / "OS" / "Work Order" => resource="order"
|
|
37
|
-
- To list/search => operation="getAll"
|
|
38
|
-
Anything outside these lists will throw a fatal error.
|
|
39
|
-
`.trim();
|
|
40
|
-
class Confirm8AgentTool {
|
|
3
|
+
exports.Confirm8OSTool = void 0;
|
|
4
|
+
const confirm8_utils_1 = require("./confirm8.utils");
|
|
5
|
+
/**
|
|
6
|
+
* CONFIRM8 OS TOOL (CHUMBED)
|
|
7
|
+
* - resource is ALWAYS "order"
|
|
8
|
+
* - operation is ALWAYS "getAll" OR "get" (derived only from presence of recordId)
|
|
9
|
+
* - dates are ALWAYS ISO YYYY-MM-DD (validated / computed here)
|
|
10
|
+
*
|
|
11
|
+
* This is the recommended single-tool version to use inside an AI Agent.
|
|
12
|
+
* The agent never sees 'resource' or 'operation' parameters, so it cannot fill them wrong.
|
|
13
|
+
*/
|
|
14
|
+
class Confirm8OSTool {
|
|
41
15
|
constructor() {
|
|
42
16
|
this.description = {
|
|
43
|
-
displayName: "Confirm8 AI Tool",
|
|
44
|
-
name: "
|
|
17
|
+
displayName: "Confirm8 OS (Chumbed AI Tool)",
|
|
18
|
+
name: "confirm8OsTool",
|
|
45
19
|
icon: "file:tool.svg",
|
|
46
20
|
group: ["transform"],
|
|
47
21
|
version: 1,
|
|
48
|
-
description:
|
|
49
|
-
defaults: {
|
|
50
|
-
name: "Confirm8 AI Tool",
|
|
51
|
-
},
|
|
52
|
-
usableAsTool: true,
|
|
22
|
+
description: "Work Orders (OS) tool for Confirm8. CHUMBED: resource/order is fixed; operation is derived internally (getAll vs get). Dates are always ISO YYYY-MM-DD.",
|
|
23
|
+
defaults: { name: "Confirm8 OS" },
|
|
53
24
|
inputs: ["main"],
|
|
54
25
|
outputs: ["main"],
|
|
55
26
|
properties: [
|
|
56
|
-
// API Configuration
|
|
57
27
|
{
|
|
58
28
|
displayName: "Base URL",
|
|
59
29
|
name: "baseUrl",
|
|
@@ -71,208 +41,97 @@ class Confirm8AgentTool {
|
|
|
71
41
|
required: true,
|
|
72
42
|
},
|
|
73
43
|
{
|
|
74
|
-
displayName: "
|
|
44
|
+
displayName: "API Domain",
|
|
75
45
|
name: "apiDomain",
|
|
76
46
|
type: "string",
|
|
77
47
|
default: "",
|
|
78
48
|
required: true,
|
|
79
49
|
},
|
|
80
50
|
{
|
|
81
|
-
displayName: "
|
|
51
|
+
displayName: "API Key Token",
|
|
82
52
|
name: "apiKeyToken",
|
|
83
53
|
type: "string",
|
|
84
54
|
typeOptions: { password: true },
|
|
85
55
|
default: "",
|
|
86
56
|
required: true,
|
|
87
57
|
},
|
|
88
|
-
// Tool parameters
|
|
89
58
|
{
|
|
90
|
-
displayName: "
|
|
91
|
-
name: "
|
|
92
|
-
type: "
|
|
93
|
-
|
|
94
|
-
{
|
|
95
|
-
name: "User",
|
|
96
|
-
value: "user",
|
|
97
|
-
description: "Users/Employees/Funcionários",
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
name: "Client",
|
|
101
|
-
value: "client",
|
|
102
|
-
description: "Clients/Customers/Clientes",
|
|
103
|
-
},
|
|
104
|
-
{ name: "Item", value: "item", description: "Items/Itens" },
|
|
105
|
-
{
|
|
106
|
-
name: "Item Type",
|
|
107
|
-
value: "itemType",
|
|
108
|
-
description: "Item Types/Tipos",
|
|
109
|
-
},
|
|
110
|
-
{
|
|
111
|
-
name: "Task",
|
|
112
|
-
value: "task",
|
|
113
|
-
description: "Tasks/Tarefas/Checklists",
|
|
114
|
-
},
|
|
115
|
-
{
|
|
116
|
-
name: "Service",
|
|
117
|
-
value: "service",
|
|
118
|
-
description: "Services/Serviços",
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
name: "Product",
|
|
122
|
-
value: "product",
|
|
123
|
-
description: "Products/Produtos",
|
|
124
|
-
},
|
|
125
|
-
{
|
|
126
|
-
name: "Order (OS)",
|
|
127
|
-
value: "order",
|
|
128
|
-
description: "Work Orders/OS/Ordens de Serviço/WOS",
|
|
129
|
-
},
|
|
130
|
-
{
|
|
131
|
-
name: "Modality",
|
|
132
|
-
value: "modality",
|
|
133
|
-
description: "Modalities/Modalidades",
|
|
134
|
-
},
|
|
135
|
-
{ name: "Ticket", value: "ticket", description: "Tickets/Chamados" },
|
|
136
|
-
{
|
|
137
|
-
name: "Property",
|
|
138
|
-
value: "property",
|
|
139
|
-
description: "Properties/Propriedades",
|
|
140
|
-
},
|
|
141
|
-
],
|
|
142
|
-
default: "user",
|
|
143
|
-
description: AGENT_USAGE_NOTE,
|
|
59
|
+
displayName: "Session ID",
|
|
60
|
+
name: "sessionId",
|
|
61
|
+
type: "string",
|
|
62
|
+
default: "",
|
|
144
63
|
},
|
|
145
64
|
{
|
|
146
|
-
displayName: "
|
|
147
|
-
name: "
|
|
148
|
-
type: "
|
|
149
|
-
|
|
150
|
-
{
|
|
151
|
-
name: "Get All (List)",
|
|
152
|
-
value: "getAll",
|
|
153
|
-
description: AGENT_USAGE_NOTE,
|
|
154
|
-
},
|
|
155
|
-
{
|
|
156
|
-
name: "Get (Single)",
|
|
157
|
-
value: "get",
|
|
158
|
-
description: AGENT_USAGE_NOTE,
|
|
159
|
-
},
|
|
160
|
-
{
|
|
161
|
-
name: "Create",
|
|
162
|
-
value: "create",
|
|
163
|
-
description: AGENT_USAGE_NOTE,
|
|
164
|
-
},
|
|
165
|
-
{
|
|
166
|
-
name: "Update",
|
|
167
|
-
value: "update",
|
|
168
|
-
description: AGENT_USAGE_NOTE,
|
|
169
|
-
},
|
|
170
|
-
{
|
|
171
|
-
name: "Activate",
|
|
172
|
-
value: "activate",
|
|
173
|
-
description: AGENT_USAGE_NOTE,
|
|
174
|
-
},
|
|
175
|
-
{
|
|
176
|
-
name: "Deactivate",
|
|
177
|
-
value: "deactivate",
|
|
178
|
-
description: AGENT_USAGE_NOTE,
|
|
179
|
-
},
|
|
180
|
-
],
|
|
181
|
-
default: "getAll",
|
|
182
|
-
description: AGENT_USAGE_NOTE,
|
|
65
|
+
displayName: "User Query (Optional)",
|
|
66
|
+
name: "chatinput",
|
|
67
|
+
type: "string",
|
|
68
|
+
default: "",
|
|
183
69
|
},
|
|
70
|
+
// If filled, tool performs GET by ID; otherwise, GET ALL (list)
|
|
184
71
|
{
|
|
185
|
-
displayName: "
|
|
72
|
+
displayName: "OS ID (recordId)",
|
|
186
73
|
name: "recordId",
|
|
187
74
|
type: "string",
|
|
188
75
|
default: "",
|
|
189
|
-
description: "
|
|
76
|
+
description: "If provided, fetches a single OS (get). If empty, lists OS (getAll).",
|
|
190
77
|
},
|
|
78
|
+
// Listing options (only relevant when recordId is empty)
|
|
191
79
|
{
|
|
192
|
-
displayName: "
|
|
193
|
-
name: "
|
|
80
|
+
displayName: "Date Range",
|
|
81
|
+
name: "dateRange",
|
|
82
|
+
type: "options",
|
|
83
|
+
default: "thisWeek",
|
|
84
|
+
displayOptions: { show: { recordId: [""] } },
|
|
85
|
+
options: [
|
|
86
|
+
{ name: "This week (Mon..Sun)", value: "thisWeek" },
|
|
87
|
+
{ name: "Custom", value: "custom" },
|
|
88
|
+
],
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
displayName: "Start Date (YYYY-MM-DD)",
|
|
92
|
+
name: "startDate",
|
|
194
93
|
type: "string",
|
|
195
94
|
default: "",
|
|
196
|
-
|
|
95
|
+
displayOptions: { show: { dateRange: ["custom"], recordId: [""] } },
|
|
197
96
|
},
|
|
198
97
|
{
|
|
199
|
-
displayName: "
|
|
200
|
-
name: "
|
|
98
|
+
displayName: "End Date (YYYY-MM-DD)",
|
|
99
|
+
name: "endDate",
|
|
201
100
|
type: "string",
|
|
202
101
|
default: "",
|
|
203
|
-
|
|
102
|
+
displayOptions: { show: { dateRange: ["custom"], recordId: [""] } },
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
displayName: "Date Field",
|
|
106
|
+
name: "dateField",
|
|
107
|
+
type: "options",
|
|
108
|
+
default: "created_at",
|
|
109
|
+
displayOptions: { show: { recordId: [""] } },
|
|
110
|
+
options: [
|
|
111
|
+
{ name: "created_at (recommended)", value: "created_at" },
|
|
112
|
+
{ name: "date", value: "date" },
|
|
113
|
+
{ name: "data", value: "data" },
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
displayName: "Per Page",
|
|
118
|
+
name: "perPage",
|
|
119
|
+
type: "number",
|
|
120
|
+
default: 50,
|
|
121
|
+
displayOptions: { show: { recordId: [""] } },
|
|
122
|
+
typeOptions: { minValue: 1, maxValue: 200 },
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
displayName: "Page",
|
|
126
|
+
name: "page",
|
|
127
|
+
type: "number",
|
|
128
|
+
default: 1,
|
|
129
|
+
displayOptions: { show: { recordId: [""] } },
|
|
130
|
+
typeOptions: { minValue: 1 },
|
|
204
131
|
},
|
|
205
132
|
],
|
|
206
133
|
};
|
|
207
134
|
}
|
|
208
|
-
/**
|
|
209
|
-
* Parse natural date queries into filter JSON
|
|
210
|
-
*/
|
|
211
|
-
parseDateQuery(query) {
|
|
212
|
-
const now = new Date();
|
|
213
|
-
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
214
|
-
query = query.toLowerCase().trim();
|
|
215
|
-
// Helper to format date as YYYY-MM-DD
|
|
216
|
-
const formatDate = (date) => {
|
|
217
|
-
return date.toISOString().split("T")[0];
|
|
218
|
-
};
|
|
219
|
-
// Today
|
|
220
|
-
if (query.includes("hoje") || query.includes("today")) {
|
|
221
|
-
const endOfDay = new Date(today);
|
|
222
|
-
endOfDay.setHours(23, 59, 59, 999);
|
|
223
|
-
return {
|
|
224
|
-
start_date: { gte: formatDate(today) },
|
|
225
|
-
end_date: { lte: formatDate(endOfDay) },
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
// This week / semana atual
|
|
229
|
-
if (query.includes("semana") || query.includes("week")) {
|
|
230
|
-
const dayOfWeek = today.getDay();
|
|
231
|
-
const diff = dayOfWeek === 0 ? -6 : 1 - dayOfWeek; // Monday is start
|
|
232
|
-
const weekStart = new Date(today);
|
|
233
|
-
weekStart.setDate(today.getDate() + diff);
|
|
234
|
-
const weekEnd = new Date(weekStart);
|
|
235
|
-
weekEnd.setDate(weekStart.getDate() + 6);
|
|
236
|
-
return {
|
|
237
|
-
start_date: { gte: formatDate(weekStart) },
|
|
238
|
-
end_date: { lte: formatDate(weekEnd) },
|
|
239
|
-
};
|
|
240
|
-
}
|
|
241
|
-
// This month / mês atual
|
|
242
|
-
if (query.includes("mês") ||
|
|
243
|
-
query.includes("mes") ||
|
|
244
|
-
query.includes("month")) {
|
|
245
|
-
const monthStart = new Date(now.getFullYear(), now.getMonth(), 1);
|
|
246
|
-
const monthEnd = new Date(now.getFullYear(), now.getMonth() + 1, 0);
|
|
247
|
-
return {
|
|
248
|
-
start_date: { gte: formatDate(monthStart) },
|
|
249
|
-
end_date: { lte: formatDate(monthEnd) },
|
|
250
|
-
};
|
|
251
|
-
}
|
|
252
|
-
// Last N days
|
|
253
|
-
const lastDaysMatch = query.match(/últimos?\s+(\d+)\s+dias?|last\s+(\d+)\s+days?/);
|
|
254
|
-
if (lastDaysMatch) {
|
|
255
|
-
const days = parseInt(lastDaysMatch[1] || lastDaysMatch[2]);
|
|
256
|
-
const startDate = new Date(today);
|
|
257
|
-
startDate.setDate(today.getDate() - days);
|
|
258
|
-
return {
|
|
259
|
-
start_date: { gte: formatDate(startDate) },
|
|
260
|
-
end_date: { lte: formatDate(today) },
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
// Next N days
|
|
264
|
-
const nextDaysMatch = query.match(/próximos?\s+(\d+)\s+dias?|next\s+(\d+)\s+days?/);
|
|
265
|
-
if (nextDaysMatch) {
|
|
266
|
-
const days = parseInt(nextDaysMatch[1] || nextDaysMatch[2]);
|
|
267
|
-
const endDate = new Date(today);
|
|
268
|
-
endDate.setDate(today.getDate() + days);
|
|
269
|
-
return {
|
|
270
|
-
start_date: { gte: formatDate(today) },
|
|
271
|
-
end_date: { lte: formatDate(endDate) },
|
|
272
|
-
};
|
|
273
|
-
}
|
|
274
|
-
return null;
|
|
275
|
-
}
|
|
276
135
|
async execute() {
|
|
277
136
|
const items = this.getInputData();
|
|
278
137
|
const returnData = [];
|
|
@@ -282,381 +141,98 @@ class Confirm8AgentTool {
|
|
|
282
141
|
const bearerToken = this.getNodeParameter("bearerToken", i);
|
|
283
142
|
const apiDomain = this.getNodeParameter("apiDomain", i);
|
|
284
143
|
const apiKeyToken = this.getNodeParameter("apiKeyToken", i);
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
const recordId = this.getNodeParameter("recordId", i, "");
|
|
288
|
-
//
|
|
289
|
-
|
|
290
|
-
const
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
}
|
|
307
|
-
catch (e) {
|
|
308
|
-
// If not JSON, try to parse as natural language date query
|
|
309
|
-
const parsedDate = this.parseDateQuery(filtersParam);
|
|
310
|
-
if (parsedDate) {
|
|
311
|
-
filters = parsedDate;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
// Aggressive normalization - EXPAND THIS
|
|
316
|
-
const resourceMap = {
|
|
317
|
-
// Standard
|
|
318
|
-
users: "user",
|
|
319
|
-
usuarios: "user",
|
|
320
|
-
usuários: "user",
|
|
321
|
-
employees: "user",
|
|
322
|
-
funcionários: "user",
|
|
323
|
-
funcionarios: "user",
|
|
324
|
-
clients: "client",
|
|
325
|
-
clientes: "client",
|
|
326
|
-
customers: "client",
|
|
327
|
-
items: "item",
|
|
328
|
-
itens: "item",
|
|
329
|
-
itemtypes: "itemType",
|
|
330
|
-
tipos: "itemType",
|
|
331
|
-
tasks: "task",
|
|
332
|
-
tarefas: "task",
|
|
333
|
-
services: "service",
|
|
334
|
-
serviços: "service",
|
|
335
|
-
servicos: "service",
|
|
336
|
-
products: "product",
|
|
337
|
-
produtos: "product",
|
|
338
|
-
modalities: "modality",
|
|
339
|
-
modalidades: "modality",
|
|
340
|
-
tickets: "ticket",
|
|
341
|
-
chamados: "ticket",
|
|
342
|
-
properties: "property",
|
|
343
|
-
propriedades: "property",
|
|
344
|
-
// CRITICAL: OS mappings
|
|
345
|
-
os: "order",
|
|
346
|
-
"o.s": "order",
|
|
347
|
-
"o.s.": "order",
|
|
348
|
-
orders: "order",
|
|
349
|
-
ordens: "order",
|
|
350
|
-
ordem: "order",
|
|
351
|
-
"ordem de serviço": "order",
|
|
352
|
-
"ordem de servico": "order",
|
|
353
|
-
"ordens de serviço": "order",
|
|
354
|
-
"ordens de servico": "order",
|
|
355
|
-
wos: "order",
|
|
356
|
-
"work order": "order",
|
|
357
|
-
"work orders": "order",
|
|
358
|
-
pedidos: "order",
|
|
359
|
-
pedido: "order",
|
|
360
|
-
};
|
|
361
|
-
const operationMap = {
|
|
362
|
-
// List/Get All
|
|
363
|
-
list: "getAll",
|
|
364
|
-
listar: "getAll",
|
|
365
|
-
mostrar: "getAll",
|
|
366
|
-
buscar: "getAll",
|
|
367
|
-
busque: "getAll",
|
|
368
|
-
"buscar todos": "getAll",
|
|
369
|
-
"buscar todas": "getAll",
|
|
370
|
-
"buscar todo": "getAll",
|
|
371
|
-
"buscar toda": "getAll",
|
|
372
|
-
"get all": "getAll",
|
|
373
|
-
"show all": "getAll",
|
|
374
|
-
"list all": "getAll",
|
|
375
|
-
todos: "getAll",
|
|
376
|
-
todas: "getAll",
|
|
377
|
-
"obter todos": "getAll",
|
|
378
|
-
"obter todas": "getAll",
|
|
379
|
-
"pegar todos": "getAll",
|
|
380
|
-
"pegar todas": "getAll",
|
|
381
|
-
// Get Single
|
|
382
|
-
obter: "get",
|
|
383
|
-
pegar: "get",
|
|
384
|
-
ver: "get",
|
|
385
|
-
visualizar: "get",
|
|
386
|
-
// Create
|
|
387
|
-
criar: "create",
|
|
388
|
-
adicionar: "create",
|
|
389
|
-
add: "create",
|
|
390
|
-
novo: "create",
|
|
391
|
-
nova: "create",
|
|
392
|
-
new: "create",
|
|
393
|
-
// Update
|
|
394
|
-
atualizar: "update",
|
|
395
|
-
modificar: "update",
|
|
396
|
-
modify: "update",
|
|
397
|
-
editar: "update",
|
|
398
|
-
edit: "update",
|
|
399
|
-
// Activate/Deactivate
|
|
400
|
-
ativar: "activate",
|
|
401
|
-
enable: "activate",
|
|
402
|
-
habilitar: "activate",
|
|
403
|
-
desativar: "deactivate",
|
|
404
|
-
disable: "deactivate",
|
|
405
|
-
desabilitar: "deactivate",
|
|
406
|
-
};
|
|
407
|
-
// Normalize - clean and map
|
|
408
|
-
const normalizeKey = (value) => value
|
|
409
|
-
.toLowerCase()
|
|
410
|
-
.normalize("NFD")
|
|
411
|
-
.replace(/\p{Diacritic}/gu, "")
|
|
412
|
-
.replace(/[^a-z0-9\s.\-_/]/g, " ")
|
|
413
|
-
.trim()
|
|
414
|
-
.replace(/\s+/g, " ");
|
|
415
|
-
const cleanResource = normalizeKey(resource);
|
|
416
|
-
const cleanOperation = normalizeKey(operation);
|
|
417
|
-
resource = resourceMap[cleanResource] || resource;
|
|
418
|
-
operation = operationMap[cleanOperation] || operation;
|
|
419
|
-
// If still not valid, throw clear error
|
|
420
|
-
const validResources = VALID_RESOURCES;
|
|
421
|
-
const validOperations = VALID_OPERATIONS;
|
|
422
|
-
if (!validResources.includes(resource)) {
|
|
423
|
-
throw new Error(`Invalid resource: "${resource}". Must be one of: ${validResources.join(", ")}. ` + `For OS/Ordem de Serviço use "order".`);
|
|
424
|
-
}
|
|
425
|
-
if (!validOperations.includes(operation)) {
|
|
426
|
-
throw new Error(`Invalid operation: "${operation}". Must be one of: ${validOperations.join(", ")}. ` + `To list/search use "getAll".`);
|
|
427
|
-
}
|
|
428
|
-
// Resource config with relations
|
|
429
|
-
const resourceConfig = {
|
|
430
|
-
user: {
|
|
431
|
-
endpoint: "users",
|
|
432
|
-
relations: [
|
|
433
|
-
"clients",
|
|
434
|
-
"attachments",
|
|
435
|
-
"permissions",
|
|
436
|
-
"device",
|
|
437
|
-
"employee",
|
|
438
|
-
],
|
|
439
|
-
},
|
|
440
|
-
client: {
|
|
441
|
-
endpoint: "clients",
|
|
442
|
-
relations: [
|
|
443
|
-
"wos",
|
|
444
|
-
"items",
|
|
445
|
-
"employees",
|
|
446
|
-
"headquarter",
|
|
447
|
-
"files",
|
|
448
|
-
"userGroup",
|
|
449
|
-
"properties",
|
|
450
|
-
],
|
|
451
|
-
},
|
|
452
|
-
item: {
|
|
453
|
-
endpoint: "items",
|
|
454
|
-
relations: [
|
|
455
|
-
"client",
|
|
456
|
-
"item_type",
|
|
457
|
-
"properties",
|
|
458
|
-
"parent",
|
|
459
|
-
"children",
|
|
460
|
-
"collects",
|
|
461
|
-
"wos",
|
|
462
|
-
],
|
|
463
|
-
},
|
|
464
|
-
itemType: {
|
|
465
|
-
endpoint: "itemTypes",
|
|
466
|
-
relations: ["properties"],
|
|
467
|
-
},
|
|
468
|
-
task: {
|
|
469
|
-
endpoint: "tasks",
|
|
470
|
-
relations: ["itemType", "activities", "wos", "modalities"],
|
|
471
|
-
},
|
|
472
|
-
service: {
|
|
473
|
-
endpoint: "services",
|
|
474
|
-
relations: ["task"],
|
|
475
|
-
},
|
|
476
|
-
product: {
|
|
477
|
-
endpoint: "products",
|
|
478
|
-
relations: [],
|
|
479
|
-
},
|
|
480
|
-
order: {
|
|
481
|
-
endpoint: "wos",
|
|
482
|
-
relations: [
|
|
483
|
-
"client",
|
|
484
|
-
"modalities",
|
|
485
|
-
"tasks",
|
|
486
|
-
"pivot_tasks",
|
|
487
|
-
"products",
|
|
488
|
-
"users",
|
|
489
|
-
"items",
|
|
490
|
-
"tickets",
|
|
491
|
-
"services",
|
|
492
|
-
"collects",
|
|
493
|
-
"attachments",
|
|
494
|
-
],
|
|
495
|
-
},
|
|
496
|
-
modality: {
|
|
497
|
-
endpoint: "modalities",
|
|
498
|
-
relations: ["tasks"],
|
|
499
|
-
},
|
|
500
|
-
ticket: {
|
|
501
|
-
endpoint: "tickets",
|
|
502
|
-
relations: [
|
|
503
|
-
"client",
|
|
504
|
-
"subject_category",
|
|
505
|
-
"category",
|
|
506
|
-
"status",
|
|
507
|
-
"attachments",
|
|
508
|
-
"item",
|
|
509
|
-
"owner",
|
|
510
|
-
"priority",
|
|
511
|
-
"users",
|
|
512
|
-
"orders",
|
|
513
|
-
"properties",
|
|
514
|
-
],
|
|
515
|
-
},
|
|
516
|
-
property: {
|
|
517
|
-
endpoint: "properties",
|
|
518
|
-
relations: [],
|
|
519
|
-
},
|
|
520
|
-
};
|
|
521
|
-
const config = resourceConfig[resource];
|
|
522
|
-
const baseEndpoint = config.endpoint;
|
|
523
|
-
let endpoint = "";
|
|
524
|
-
let method = "GET";
|
|
525
|
-
let body = {};
|
|
526
|
-
// Build endpoint
|
|
527
|
-
switch (operation) {
|
|
528
|
-
case "getAll":
|
|
529
|
-
endpoint = `/v3/${baseEndpoint}`;
|
|
530
|
-
break;
|
|
531
|
-
case "get":
|
|
532
|
-
if (!recordId)
|
|
533
|
-
throw new Error("recordId required");
|
|
534
|
-
endpoint = `/v3/${baseEndpoint}/${recordId}`;
|
|
535
|
-
break;
|
|
536
|
-
case "create":
|
|
537
|
-
endpoint = `/v3/${baseEndpoint}`;
|
|
538
|
-
method = "POST";
|
|
539
|
-
body = data;
|
|
540
|
-
break;
|
|
541
|
-
case "update":
|
|
542
|
-
if (!recordId)
|
|
543
|
-
throw new Error("recordId required");
|
|
544
|
-
endpoint = `/v3/${baseEndpoint}/${recordId}`;
|
|
545
|
-
method = "PUT";
|
|
546
|
-
body = data;
|
|
547
|
-
break;
|
|
548
|
-
case "activate":
|
|
549
|
-
if (!recordId)
|
|
550
|
-
throw new Error("recordId required");
|
|
551
|
-
endpoint = `/v3/${baseEndpoint}/${recordId}/active`;
|
|
552
|
-
method = [
|
|
553
|
-
"client",
|
|
554
|
-
"item",
|
|
555
|
-
"itemType",
|
|
556
|
-
"task",
|
|
557
|
-
"service",
|
|
558
|
-
"product",
|
|
559
|
-
"order",
|
|
560
|
-
"modality",
|
|
561
|
-
].includes(resource)
|
|
562
|
-
? "PUT"
|
|
563
|
-
: "PATCH";
|
|
564
|
-
break;
|
|
565
|
-
case "deactivate":
|
|
566
|
-
if (!recordId)
|
|
567
|
-
throw new Error("recordId required");
|
|
568
|
-
endpoint = `/v3/${baseEndpoint}/${recordId}/inactive`;
|
|
569
|
-
method = [
|
|
570
|
-
"client",
|
|
571
|
-
"item",
|
|
572
|
-
"itemType",
|
|
573
|
-
"task",
|
|
574
|
-
"service",
|
|
575
|
-
"product",
|
|
576
|
-
"order",
|
|
577
|
-
"modality",
|
|
578
|
-
].includes(resource)
|
|
579
|
-
? "PUT"
|
|
580
|
-
: "PATCH";
|
|
581
|
-
break;
|
|
582
|
-
}
|
|
583
|
-
// Build query string
|
|
584
|
-
const queryParams = [];
|
|
585
|
-
// Add relations (only GET)
|
|
586
|
-
if (method === "GET" && config.relations.length > 0) {
|
|
587
|
-
config.relations.forEach((relation) => {
|
|
588
|
-
queryParams.push(`relations=${relation}`);
|
|
144
|
+
const sessionId = this.getNodeParameter("sessionId", i, "");
|
|
145
|
+
const chatinput = this.getNodeParameter("chatinput", i, "");
|
|
146
|
+
const recordId = this.getNodeParameter("recordId", i, "").trim();
|
|
147
|
+
// CHUMBED RESOURCE
|
|
148
|
+
const resource = "order";
|
|
149
|
+
const config = confirm8_utils_1.RESOURCE_ENDPOINTS[resource];
|
|
150
|
+
// Decide operation internally
|
|
151
|
+
const operation = recordId ? "get" : "getAll";
|
|
152
|
+
if (operation === "get") {
|
|
153
|
+
const endpoint = `/v3/${config.endpoint}/${encodeURIComponent(recordId)}`;
|
|
154
|
+
const query = config.relations?.length
|
|
155
|
+
? `?${config.relations.map((r) => `relations=${encodeURIComponent(r)}`).join("&")}`
|
|
156
|
+
: "";
|
|
157
|
+
const data = await confirm8_utils_1.confirm8Request.call(this, i, {
|
|
158
|
+
baseUrl,
|
|
159
|
+
bearerToken,
|
|
160
|
+
apiDomain,
|
|
161
|
+
apiKeyToken,
|
|
162
|
+
method: "GET",
|
|
163
|
+
endpoint,
|
|
164
|
+
query,
|
|
589
165
|
});
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
});
|
|
166
|
+
returnData.push({
|
|
167
|
+
json: {
|
|
168
|
+
success: true,
|
|
169
|
+
fixed: { resource, operation },
|
|
170
|
+
request: { sessionId, chatinput, recordId, endpoint },
|
|
171
|
+
data,
|
|
172
|
+
},
|
|
173
|
+
pairedItem: { item: i },
|
|
599
174
|
});
|
|
175
|
+
continue;
|
|
600
176
|
}
|
|
601
|
-
//
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
177
|
+
// operation === getAll
|
|
178
|
+
const dateRange = this.getNodeParameter("dateRange", i);
|
|
179
|
+
const dateField = this.getNodeParameter("dateField", i);
|
|
180
|
+
let start;
|
|
181
|
+
let end;
|
|
182
|
+
if (dateRange === "custom") {
|
|
183
|
+
start = this.getNodeParameter("startDate", i) || "";
|
|
184
|
+
end = this.getNodeParameter("endDate", i) || "";
|
|
185
|
+
if (!start || !end) {
|
|
186
|
+
throw new Error("When Date Range is Custom, startDate and endDate are required.");
|
|
187
|
+
}
|
|
188
|
+
(0, confirm8_utils_1.assertIsoDate)(start, "startDate");
|
|
189
|
+
(0, confirm8_utils_1.assertIsoDate)(end, "endDate");
|
|
605
190
|
}
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
headers: {
|
|
611
|
-
Authorization: `Bearer ${bearerToken}`,
|
|
612
|
-
"X-API-DOMAIN": apiDomain,
|
|
613
|
-
"X-APIKEY-TOKEN": apiKeyToken,
|
|
614
|
-
"Content-Type": "application/json",
|
|
615
|
-
},
|
|
616
|
-
json: true,
|
|
617
|
-
};
|
|
618
|
-
if (method !== "GET" &&
|
|
619
|
-
method !== "DELETE" &&
|
|
620
|
-
Object.keys(body).length > 0) {
|
|
621
|
-
options.body = body;
|
|
191
|
+
else {
|
|
192
|
+
const r = (0, confirm8_utils_1.getThisWeekRange)(new Date());
|
|
193
|
+
start = r.start;
|
|
194
|
+
end = r.end;
|
|
622
195
|
}
|
|
623
|
-
const
|
|
196
|
+
const endpoint = `/v3/${config.endpoint}`;
|
|
197
|
+
const filters = { [dateField]: { gte: start, lte: end } };
|
|
198
|
+
const page = this.getNodeParameter("page", i);
|
|
199
|
+
const perPage = this.getNodeParameter("perPage", i);
|
|
200
|
+
const query = (0, confirm8_utils_1.buildQueryParams)(config.relations, filters);
|
|
201
|
+
const pagination = `&page=${encodeURIComponent(String(page))}&per_page=${encodeURIComponent(String(perPage))}`;
|
|
202
|
+
const finalQuery = query ? `${query}${pagination}` : `?page=${page}&per_page=${perPage}`;
|
|
203
|
+
const data = await confirm8_utils_1.confirm8Request.call(this, i, {
|
|
204
|
+
baseUrl,
|
|
205
|
+
bearerToken,
|
|
206
|
+
apiDomain,
|
|
207
|
+
apiKeyToken,
|
|
208
|
+
method: "GET",
|
|
209
|
+
endpoint,
|
|
210
|
+
query: finalQuery,
|
|
211
|
+
});
|
|
624
212
|
returnData.push({
|
|
625
213
|
json: {
|
|
626
214
|
success: true,
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
method,
|
|
640
|
-
data: responseData,
|
|
215
|
+
fixed: { resource, operation },
|
|
216
|
+
request: {
|
|
217
|
+
sessionId,
|
|
218
|
+
chatinput,
|
|
219
|
+
endpoint,
|
|
220
|
+
dateField,
|
|
221
|
+
startDate: start,
|
|
222
|
+
endDate: end,
|
|
223
|
+
page,
|
|
224
|
+
perPage,
|
|
225
|
+
},
|
|
226
|
+
data,
|
|
641
227
|
},
|
|
642
228
|
pairedItem: { item: i },
|
|
643
229
|
});
|
|
644
230
|
}
|
|
645
|
-
catch (
|
|
646
|
-
|
|
647
|
-
returnData.push({
|
|
648
|
-
json: {
|
|
649
|
-
success: false,
|
|
650
|
-
error: error.message || "Unknown error",
|
|
651
|
-
},
|
|
652
|
-
pairedItem: { item: i },
|
|
653
|
-
});
|
|
654
|
-
continue;
|
|
655
|
-
}
|
|
656
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), error, { itemIndex: i });
|
|
231
|
+
catch (err) {
|
|
232
|
+
throw (0, confirm8_utils_1.toNodeError)(this.getNode(), err, i);
|
|
657
233
|
}
|
|
658
234
|
}
|
|
659
235
|
return [returnData];
|
|
660
236
|
}
|
|
661
237
|
}
|
|
662
|
-
exports.
|
|
238
|
+
exports.Confirm8OSTool = Confirm8OSTool;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { IDataObject, NodeOperationError, IExecuteFunctions } from "n8n-workflow";
|
|
2
|
+
export declare const VALID_RESOURCES: readonly ["user", "client", "item", "itemType", "task", "service", "product", "order", "modality", "ticket", "property"];
|
|
3
|
+
export declare const VALID_OPERATIONS: readonly ["getAll", "get", "create", "update", "activate", "deactivate"];
|
|
4
|
+
export type Confirm8Resource = (typeof VALID_RESOURCES)[number];
|
|
5
|
+
export type Confirm8Operation = (typeof VALID_OPERATIONS)[number];
|
|
6
|
+
export declare const RESOURCE_ENDPOINTS: Record<Confirm8Resource, {
|
|
7
|
+
endpoint: string;
|
|
8
|
+
relations: string[];
|
|
9
|
+
}>;
|
|
10
|
+
export declare function assertIsoDate(dateStr: string, label: string): void;
|
|
11
|
+
export declare function formatIsoDate(d: Date): string;
|
|
12
|
+
/**
|
|
13
|
+
* Week starts on Monday (pt-BR business default).
|
|
14
|
+
* Returns inclusive start/end in YYYY-MM-DD.
|
|
15
|
+
*/
|
|
16
|
+
export declare function getThisWeekRange(now?: Date): {
|
|
17
|
+
start: string;
|
|
18
|
+
end: string;
|
|
19
|
+
};
|
|
20
|
+
/** Build query params for relations + filters in Confirm8 format. */
|
|
21
|
+
export declare function buildQueryParams(relations: string[], filters?: IDataObject): string;
|
|
22
|
+
export declare function confirm8Request(this: IExecuteFunctions, i: number, args: {
|
|
23
|
+
baseUrl: string;
|
|
24
|
+
bearerToken: string;
|
|
25
|
+
apiDomain: string;
|
|
26
|
+
apiKeyToken: string;
|
|
27
|
+
method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
28
|
+
endpoint: string;
|
|
29
|
+
query?: string;
|
|
30
|
+
body?: IDataObject;
|
|
31
|
+
}): Promise<any>;
|
|
32
|
+
export declare function toNodeError(node: any, err: unknown, i: number): NodeOperationError;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RESOURCE_ENDPOINTS = exports.VALID_OPERATIONS = exports.VALID_RESOURCES = void 0;
|
|
4
|
+
exports.assertIsoDate = assertIsoDate;
|
|
5
|
+
exports.formatIsoDate = formatIsoDate;
|
|
6
|
+
exports.getThisWeekRange = getThisWeekRange;
|
|
7
|
+
exports.buildQueryParams = buildQueryParams;
|
|
8
|
+
exports.confirm8Request = confirm8Request;
|
|
9
|
+
exports.toNodeError = toNodeError;
|
|
10
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
11
|
+
exports.VALID_RESOURCES = [
|
|
12
|
+
"user",
|
|
13
|
+
"client",
|
|
14
|
+
"item",
|
|
15
|
+
"itemType",
|
|
16
|
+
"task",
|
|
17
|
+
"service",
|
|
18
|
+
"product",
|
|
19
|
+
"order",
|
|
20
|
+
"modality",
|
|
21
|
+
"ticket",
|
|
22
|
+
"property",
|
|
23
|
+
];
|
|
24
|
+
exports.VALID_OPERATIONS = [
|
|
25
|
+
"getAll",
|
|
26
|
+
"get",
|
|
27
|
+
"create",
|
|
28
|
+
"update",
|
|
29
|
+
"activate",
|
|
30
|
+
"deactivate",
|
|
31
|
+
];
|
|
32
|
+
exports.RESOURCE_ENDPOINTS = {
|
|
33
|
+
user: {
|
|
34
|
+
endpoint: "users",
|
|
35
|
+
relations: ["clients", "attachments", "permissions", "device", "employee"],
|
|
36
|
+
},
|
|
37
|
+
client: {
|
|
38
|
+
endpoint: "clients",
|
|
39
|
+
relations: [
|
|
40
|
+
"address",
|
|
41
|
+
"contacts",
|
|
42
|
+
"items",
|
|
43
|
+
"tickets",
|
|
44
|
+
"orders",
|
|
45
|
+
"properties",
|
|
46
|
+
"attachments",
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
item: {
|
|
50
|
+
endpoint: "items",
|
|
51
|
+
relations: ["client", "itemType", "properties", "attachments"],
|
|
52
|
+
},
|
|
53
|
+
itemType: { endpoint: "item-types", relations: ["properties"] },
|
|
54
|
+
task: {
|
|
55
|
+
endpoint: "tasks",
|
|
56
|
+
relations: ["itemType", "modality", "services", "products"],
|
|
57
|
+
},
|
|
58
|
+
service: { endpoint: "services", relations: ["task"] },
|
|
59
|
+
product: { endpoint: "products", relations: [] },
|
|
60
|
+
// IMPORTANT: Confirm8 Work Orders endpoint is 'wos'
|
|
61
|
+
order: {
|
|
62
|
+
endpoint: "wos",
|
|
63
|
+
relations: [
|
|
64
|
+
"client",
|
|
65
|
+
"modalities",
|
|
66
|
+
"tasks",
|
|
67
|
+
"pivot_tasks",
|
|
68
|
+
"products",
|
|
69
|
+
"users",
|
|
70
|
+
"items",
|
|
71
|
+
"tickets",
|
|
72
|
+
"services",
|
|
73
|
+
"collects",
|
|
74
|
+
"attachments",
|
|
75
|
+
],
|
|
76
|
+
},
|
|
77
|
+
modality: { endpoint: "modalities", relations: ["tasks"] },
|
|
78
|
+
ticket: {
|
|
79
|
+
endpoint: "tickets",
|
|
80
|
+
relations: ["client", "subject_category", "category", "user", "attachments"],
|
|
81
|
+
},
|
|
82
|
+
property: { endpoint: "properties", relations: ["client", "item", "itemType"] },
|
|
83
|
+
};
|
|
84
|
+
const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
85
|
+
function assertIsoDate(dateStr, label) {
|
|
86
|
+
if (!ISO_DATE.test(dateStr)) {
|
|
87
|
+
throw new Error(`${label} must be in YYYY-MM-DD format. Received: "${dateStr}"`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function formatIsoDate(d) {
|
|
91
|
+
const y = d.getFullYear();
|
|
92
|
+
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
93
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
94
|
+
return `${y}-${m}-${day}`;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Week starts on Monday (pt-BR business default).
|
|
98
|
+
* Returns inclusive start/end in YYYY-MM-DD.
|
|
99
|
+
*/
|
|
100
|
+
function getThisWeekRange(now = new Date()) {
|
|
101
|
+
const d = new Date(now);
|
|
102
|
+
d.setHours(0, 0, 0, 0);
|
|
103
|
+
// JS: Sunday=0 ... Saturday=6
|
|
104
|
+
const day = d.getDay();
|
|
105
|
+
const diffToMonday = day === 0 ? -6 : 1 - day; // if Sunday -> go back 6 days
|
|
106
|
+
const startDate = new Date(d);
|
|
107
|
+
startDate.setDate(d.getDate() + diffToMonday);
|
|
108
|
+
const endDate = new Date(startDate);
|
|
109
|
+
endDate.setDate(startDate.getDate() + 6);
|
|
110
|
+
return { start: formatIsoDate(startDate), end: formatIsoDate(endDate) };
|
|
111
|
+
}
|
|
112
|
+
/** Build query params for relations + filters in Confirm8 format. */
|
|
113
|
+
function buildQueryParams(relations, filters) {
|
|
114
|
+
const queryParams = [];
|
|
115
|
+
if (relations?.length) {
|
|
116
|
+
for (const rel of relations)
|
|
117
|
+
queryParams.push(`relations=${encodeURIComponent(rel)}`);
|
|
118
|
+
}
|
|
119
|
+
if (filters && Object.keys(filters).length) {
|
|
120
|
+
for (const field of Object.keys(filters)) {
|
|
121
|
+
const operators = filters[field];
|
|
122
|
+
for (const op of Object.keys(operators)) {
|
|
123
|
+
const value = operators[op];
|
|
124
|
+
queryParams.push(`filters[${encodeURIComponent(field)}][${encodeURIComponent(op)}]=${encodeURIComponent(String(value))}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return queryParams.length ? `?${queryParams.join("&")}` : "";
|
|
129
|
+
}
|
|
130
|
+
function confirm8Request(i, args) {
|
|
131
|
+
const { baseUrl, bearerToken, apiDomain, apiKeyToken, method, endpoint, query, body } = args;
|
|
132
|
+
const uri = `${baseUrl}${endpoint}${query ?? ""}`;
|
|
133
|
+
const options = {
|
|
134
|
+
method,
|
|
135
|
+
uri,
|
|
136
|
+
headers: {
|
|
137
|
+
Authorization: `Bearer ${bearerToken}`,
|
|
138
|
+
"X-API-DOMAIN": apiDomain,
|
|
139
|
+
"X-APIKEY-TOKEN": apiKeyToken,
|
|
140
|
+
"Content-Type": "application/json",
|
|
141
|
+
},
|
|
142
|
+
json: true,
|
|
143
|
+
};
|
|
144
|
+
if (body && method !== "GET" && method !== "DELETE") {
|
|
145
|
+
options.body = body;
|
|
146
|
+
}
|
|
147
|
+
return this.helpers.request(options);
|
|
148
|
+
}
|
|
149
|
+
function toNodeError(node, err, i) {
|
|
150
|
+
if (err instanceof n8n_workflow_1.NodeOperationError)
|
|
151
|
+
return err;
|
|
152
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
153
|
+
return new n8n_workflow_1.NodeOperationError(node, message, { itemIndex: i });
|
|
154
|
+
}
|