n8n-nodes-confirm8 0.20.0 → 0.22.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,5 +1,9 @@
|
|
|
1
|
-
import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from
|
|
1
|
+
import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from "n8n-workflow";
|
|
2
2
|
export declare class Confirm8AgentTool implements INodeType {
|
|
3
3
|
description: INodeTypeDescription;
|
|
4
|
+
/**
|
|
5
|
+
* Parse natural date queries into filter JSON
|
|
6
|
+
*/
|
|
7
|
+
private parseDateQuery;
|
|
4
8
|
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
5
9
|
}
|
|
@@ -2,129 +2,292 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Confirm8AgentTool = void 0;
|
|
4
4
|
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
// -----------------------------------------------------------------------------
|
|
6
|
+
// STRICT ALLOWED VALUES (used both for UI + for agent/tool schema guidance)
|
|
7
|
+
// IMPORTANT: Any agent calling this tool MUST use ONLY these exact tokens.
|
|
8
|
+
// -----------------------------------------------------------------------------
|
|
9
|
+
const VALID_RESOURCES = [
|
|
10
|
+
"user",
|
|
11
|
+
"client",
|
|
12
|
+
"item",
|
|
13
|
+
"itemType",
|
|
14
|
+
"task",
|
|
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();
|
|
5
40
|
class Confirm8AgentTool {
|
|
6
41
|
constructor() {
|
|
7
42
|
this.description = {
|
|
8
|
-
displayName:
|
|
9
|
-
name:
|
|
10
|
-
icon:
|
|
11
|
-
group: [
|
|
43
|
+
displayName: "Confirm8 AI Tool",
|
|
44
|
+
name: "confirm8AgentTool",
|
|
45
|
+
icon: "file:tool.svg",
|
|
46
|
+
group: ["transform"],
|
|
12
47
|
version: 1,
|
|
13
|
-
description: 'AI
|
|
48
|
+
description: 'AI tool for Confirm8. IMPORTANT: For "OS/ordem de serviço" use resource="order". For dates use filters with start_date/end_date. Example: {"start_date":{"gte":"2025-11-23"},"end_date":{"lte":"2025-11-25"}}',
|
|
14
49
|
defaults: {
|
|
15
|
-
name:
|
|
50
|
+
name: "Confirm8 AI Tool",
|
|
16
51
|
},
|
|
17
52
|
usableAsTool: true,
|
|
18
|
-
inputs: [
|
|
19
|
-
outputs: [
|
|
53
|
+
inputs: ["main"],
|
|
54
|
+
outputs: ["main"],
|
|
20
55
|
properties: [
|
|
21
56
|
// API Configuration
|
|
22
57
|
{
|
|
23
|
-
displayName:
|
|
24
|
-
name:
|
|
25
|
-
type:
|
|
26
|
-
default:
|
|
27
|
-
placeholder:
|
|
58
|
+
displayName: "Base URL",
|
|
59
|
+
name: "baseUrl",
|
|
60
|
+
type: "string",
|
|
61
|
+
default: "",
|
|
62
|
+
placeholder: "https://api.confirm8.com",
|
|
28
63
|
required: true,
|
|
29
64
|
},
|
|
30
65
|
{
|
|
31
|
-
displayName:
|
|
32
|
-
name:
|
|
33
|
-
type:
|
|
66
|
+
displayName: "Bearer Token",
|
|
67
|
+
name: "bearerToken",
|
|
68
|
+
type: "string",
|
|
34
69
|
typeOptions: { password: true },
|
|
35
|
-
default:
|
|
70
|
+
default: "",
|
|
36
71
|
required: true,
|
|
37
72
|
},
|
|
38
73
|
{
|
|
39
|
-
displayName:
|
|
40
|
-
name:
|
|
41
|
-
type:
|
|
42
|
-
default:
|
|
74
|
+
displayName: "X-API-DOMAIN",
|
|
75
|
+
name: "apiDomain",
|
|
76
|
+
type: "string",
|
|
77
|
+
default: "",
|
|
43
78
|
required: true,
|
|
44
79
|
},
|
|
45
80
|
{
|
|
46
|
-
displayName:
|
|
47
|
-
name:
|
|
48
|
-
type:
|
|
81
|
+
displayName: "X-APIKEY-TOKEN",
|
|
82
|
+
name: "apiKeyToken",
|
|
83
|
+
type: "string",
|
|
49
84
|
typeOptions: { password: true },
|
|
50
|
-
default:
|
|
85
|
+
default: "",
|
|
51
86
|
required: true,
|
|
52
87
|
},
|
|
53
88
|
// Tool parameters
|
|
54
89
|
{
|
|
55
|
-
displayName:
|
|
56
|
-
name:
|
|
57
|
-
type:
|
|
90
|
+
displayName: "Resource",
|
|
91
|
+
name: "resource",
|
|
92
|
+
type: "options",
|
|
58
93
|
options: [
|
|
59
|
-
{
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
{
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
{ name:
|
|
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
|
+
},
|
|
70
141
|
],
|
|
71
|
-
default:
|
|
72
|
-
description:
|
|
142
|
+
default: "user",
|
|
143
|
+
description: AGENT_USAGE_NOTE,
|
|
73
144
|
},
|
|
74
145
|
{
|
|
75
|
-
displayName:
|
|
76
|
-
name:
|
|
77
|
-
type:
|
|
146
|
+
displayName: "Operation",
|
|
147
|
+
name: "operation",
|
|
148
|
+
type: "options",
|
|
78
149
|
options: [
|
|
79
|
-
{
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
{
|
|
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
|
+
},
|
|
85
180
|
],
|
|
86
|
-
default:
|
|
87
|
-
description:
|
|
181
|
+
default: "getAll",
|
|
182
|
+
description: AGENT_USAGE_NOTE,
|
|
88
183
|
},
|
|
89
184
|
{
|
|
90
|
-
displayName:
|
|
91
|
-
name:
|
|
92
|
-
type:
|
|
93
|
-
default:
|
|
94
|
-
description:
|
|
185
|
+
displayName: "Record ID",
|
|
186
|
+
name: "recordId",
|
|
187
|
+
type: "string",
|
|
188
|
+
default: "",
|
|
189
|
+
description: "Record ID (only for get/update/activate/deactivate)",
|
|
95
190
|
},
|
|
96
191
|
{
|
|
97
|
-
displayName:
|
|
98
|
-
name:
|
|
99
|
-
type:
|
|
100
|
-
default:
|
|
101
|
-
description:
|
|
192
|
+
displayName: "Data",
|
|
193
|
+
name: "data",
|
|
194
|
+
type: "string",
|
|
195
|
+
default: "",
|
|
196
|
+
description: "JSON data (only for create/update)",
|
|
102
197
|
},
|
|
103
198
|
{
|
|
104
|
-
displayName:
|
|
105
|
-
name:
|
|
106
|
-
type:
|
|
107
|
-
default:
|
|
108
|
-
description: 'Filters as JSON
|
|
199
|
+
displayName: "Filters",
|
|
200
|
+
name: "filters",
|
|
201
|
+
type: "string",
|
|
202
|
+
default: "",
|
|
203
|
+
description: 'Filters as JSON. For dates: {"start_date":{"gte":"YYYY-MM-DD"},"end_date":{"lte":"YYYY-MM-DD"}}. For status: {"status":{"eq":"complete"}}',
|
|
109
204
|
},
|
|
110
205
|
],
|
|
111
206
|
};
|
|
112
207
|
}
|
|
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
|
+
}
|
|
113
276
|
async execute() {
|
|
114
277
|
const items = this.getInputData();
|
|
115
278
|
const returnData = [];
|
|
116
279
|
for (let i = 0; i < items.length; i++) {
|
|
117
280
|
try {
|
|
118
|
-
const baseUrl = this.getNodeParameter(
|
|
119
|
-
const bearerToken = this.getNodeParameter(
|
|
120
|
-
const apiDomain = this.getNodeParameter(
|
|
121
|
-
const apiKeyToken = this.getNodeParameter(
|
|
122
|
-
let resource = this.getNodeParameter(
|
|
123
|
-
let operation = this.getNodeParameter(
|
|
124
|
-
const recordId = this.getNodeParameter(
|
|
281
|
+
const baseUrl = this.getNodeParameter("baseUrl", i);
|
|
282
|
+
const bearerToken = this.getNodeParameter("bearerToken", i);
|
|
283
|
+
const apiDomain = this.getNodeParameter("apiDomain", i);
|
|
284
|
+
const apiKeyToken = this.getNodeParameter("apiKeyToken", i);
|
|
285
|
+
let resource = this.getNodeParameter("resource", i, "");
|
|
286
|
+
let operation = this.getNodeParameter("operation", i, "");
|
|
287
|
+
const recordId = this.getNodeParameter("recordId", i, "");
|
|
125
288
|
// Parse data
|
|
126
289
|
let data = {};
|
|
127
|
-
const dataParam = this.getNodeParameter(
|
|
290
|
+
const dataParam = this.getNodeParameter("data", i, "");
|
|
128
291
|
if (dataParam) {
|
|
129
292
|
try {
|
|
130
293
|
data = JSON.parse(dataParam);
|
|
@@ -135,177 +298,338 @@ class Confirm8AgentTool {
|
|
|
135
298
|
}
|
|
136
299
|
// Parse filters
|
|
137
300
|
let filters = {};
|
|
138
|
-
const filtersParam = this.getNodeParameter(
|
|
301
|
+
const filtersParam = this.getNodeParameter("filters", i, "");
|
|
139
302
|
if (filtersParam) {
|
|
140
303
|
try {
|
|
304
|
+
// Try to parse as JSON first
|
|
141
305
|
filters = JSON.parse(filtersParam);
|
|
142
306
|
}
|
|
143
307
|
catch (e) {
|
|
144
|
-
//
|
|
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
|
+
}
|
|
145
313
|
}
|
|
146
314
|
}
|
|
147
|
-
//
|
|
315
|
+
// Aggressive normalization - EXPAND THIS
|
|
148
316
|
const resourceMap = {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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",
|
|
160
360
|
};
|
|
161
361
|
const operationMap = {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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",
|
|
167
406
|
};
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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".`);
|
|
172
424
|
}
|
|
173
|
-
|
|
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
|
|
174
429
|
const resourceConfig = {
|
|
175
430
|
user: {
|
|
176
|
-
endpoint:
|
|
177
|
-
relations: [
|
|
431
|
+
endpoint: "users",
|
|
432
|
+
relations: [
|
|
433
|
+
"clients",
|
|
434
|
+
"attachments",
|
|
435
|
+
"permissions",
|
|
436
|
+
"device",
|
|
437
|
+
"employee",
|
|
438
|
+
],
|
|
178
439
|
},
|
|
179
440
|
client: {
|
|
180
|
-
endpoint:
|
|
181
|
-
relations: [
|
|
441
|
+
endpoint: "clients",
|
|
442
|
+
relations: [
|
|
443
|
+
"wos",
|
|
444
|
+
"items",
|
|
445
|
+
"employees",
|
|
446
|
+
"headquarter",
|
|
447
|
+
"files",
|
|
448
|
+
"userGroup",
|
|
449
|
+
"properties",
|
|
450
|
+
],
|
|
182
451
|
},
|
|
183
452
|
item: {
|
|
184
|
-
endpoint:
|
|
185
|
-
relations: [
|
|
453
|
+
endpoint: "items",
|
|
454
|
+
relations: [
|
|
455
|
+
"client",
|
|
456
|
+
"item_type",
|
|
457
|
+
"properties",
|
|
458
|
+
"parent",
|
|
459
|
+
"children",
|
|
460
|
+
"collects",
|
|
461
|
+
"wos",
|
|
462
|
+
],
|
|
186
463
|
},
|
|
187
464
|
itemType: {
|
|
188
|
-
endpoint:
|
|
189
|
-
relations: [
|
|
465
|
+
endpoint: "itemTypes",
|
|
466
|
+
relations: ["properties"],
|
|
190
467
|
},
|
|
191
468
|
task: {
|
|
192
|
-
endpoint:
|
|
193
|
-
relations: [
|
|
469
|
+
endpoint: "tasks",
|
|
470
|
+
relations: ["itemType", "activities", "wos", "modalities"],
|
|
194
471
|
},
|
|
195
472
|
service: {
|
|
196
|
-
endpoint:
|
|
197
|
-
relations: [
|
|
473
|
+
endpoint: "services",
|
|
474
|
+
relations: ["task"],
|
|
198
475
|
},
|
|
199
476
|
product: {
|
|
200
|
-
endpoint:
|
|
201
|
-
relations: []
|
|
477
|
+
endpoint: "products",
|
|
478
|
+
relations: [],
|
|
202
479
|
},
|
|
203
480
|
order: {
|
|
204
|
-
endpoint:
|
|
205
|
-
relations: [
|
|
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
|
+
],
|
|
206
495
|
},
|
|
207
496
|
modality: {
|
|
208
|
-
endpoint:
|
|
209
|
-
relations: [
|
|
497
|
+
endpoint: "modalities",
|
|
498
|
+
relations: ["tasks"],
|
|
210
499
|
},
|
|
211
500
|
ticket: {
|
|
212
|
-
endpoint:
|
|
213
|
-
relations: [
|
|
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
|
+
],
|
|
214
515
|
},
|
|
215
516
|
property: {
|
|
216
|
-
endpoint:
|
|
217
|
-
relations: []
|
|
517
|
+
endpoint: "properties",
|
|
518
|
+
relations: [],
|
|
218
519
|
},
|
|
219
520
|
};
|
|
220
521
|
const config = resourceConfig[resource];
|
|
221
|
-
if (!config) {
|
|
222
|
-
throw new Error(`Unknown resource: ${resource}`);
|
|
223
|
-
}
|
|
224
522
|
const baseEndpoint = config.endpoint;
|
|
225
|
-
let endpoint =
|
|
226
|
-
let method =
|
|
523
|
+
let endpoint = "";
|
|
524
|
+
let method = "GET";
|
|
227
525
|
let body = {};
|
|
228
|
-
// Build endpoint
|
|
526
|
+
// Build endpoint
|
|
229
527
|
switch (operation) {
|
|
230
|
-
case
|
|
528
|
+
case "getAll":
|
|
231
529
|
endpoint = `/v3/${baseEndpoint}`;
|
|
232
530
|
break;
|
|
233
|
-
case
|
|
531
|
+
case "get":
|
|
234
532
|
if (!recordId)
|
|
235
|
-
throw new Error(
|
|
533
|
+
throw new Error("recordId required");
|
|
236
534
|
endpoint = `/v3/${baseEndpoint}/${recordId}`;
|
|
237
535
|
break;
|
|
238
|
-
case
|
|
536
|
+
case "create":
|
|
239
537
|
endpoint = `/v3/${baseEndpoint}`;
|
|
240
|
-
method =
|
|
538
|
+
method = "POST";
|
|
241
539
|
body = data;
|
|
242
540
|
break;
|
|
243
|
-
case
|
|
541
|
+
case "update":
|
|
244
542
|
if (!recordId)
|
|
245
|
-
throw new Error(
|
|
543
|
+
throw new Error("recordId required");
|
|
246
544
|
endpoint = `/v3/${baseEndpoint}/${recordId}`;
|
|
247
|
-
method =
|
|
545
|
+
method = "PUT";
|
|
248
546
|
body = data;
|
|
249
547
|
break;
|
|
250
|
-
case
|
|
548
|
+
case "activate":
|
|
251
549
|
if (!recordId)
|
|
252
|
-
throw new Error(
|
|
550
|
+
throw new Error("recordId required");
|
|
253
551
|
endpoint = `/v3/${baseEndpoint}/${recordId}/active`;
|
|
254
|
-
method = [
|
|
255
|
-
|
|
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";
|
|
256
564
|
break;
|
|
257
|
-
case
|
|
565
|
+
case "deactivate":
|
|
258
566
|
if (!recordId)
|
|
259
|
-
throw new Error(
|
|
567
|
+
throw new Error("recordId required");
|
|
260
568
|
endpoint = `/v3/${baseEndpoint}/${recordId}/inactive`;
|
|
261
|
-
method = [
|
|
262
|
-
|
|
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";
|
|
263
581
|
break;
|
|
264
|
-
default:
|
|
265
|
-
throw new Error(`Unknown operation: ${operation}`);
|
|
266
582
|
}
|
|
267
583
|
// Build query string
|
|
268
584
|
const queryParams = [];
|
|
269
|
-
// Add relations (only
|
|
270
|
-
if (method ===
|
|
271
|
-
config.relations.forEach(relation => {
|
|
585
|
+
// Add relations (only GET)
|
|
586
|
+
if (method === "GET" && config.relations.length > 0) {
|
|
587
|
+
config.relations.forEach((relation) => {
|
|
272
588
|
queryParams.push(`relations=${relation}`);
|
|
273
589
|
});
|
|
274
590
|
}
|
|
275
591
|
// Add filters
|
|
276
592
|
if (Object.keys(filters).length > 0) {
|
|
277
|
-
Object.keys(filters).forEach(field => {
|
|
593
|
+
Object.keys(filters).forEach((field) => {
|
|
278
594
|
const operators = filters[field];
|
|
279
|
-
Object.keys(operators).forEach(operator => {
|
|
595
|
+
Object.keys(operators).forEach((operator) => {
|
|
280
596
|
const value = operators[operator];
|
|
281
597
|
queryParams.push(`filters[${field}][${operator}]=${encodeURIComponent(String(value))}`);
|
|
282
598
|
});
|
|
283
599
|
});
|
|
284
600
|
}
|
|
285
|
-
//
|
|
601
|
+
// Full URL
|
|
286
602
|
let fullUrl = `${baseUrl}${endpoint}`;
|
|
287
603
|
if (queryParams.length > 0) {
|
|
288
|
-
fullUrl +=
|
|
604
|
+
fullUrl += "?" + queryParams.join("&");
|
|
289
605
|
}
|
|
290
606
|
// Make request
|
|
291
607
|
const options = {
|
|
292
608
|
method,
|
|
293
609
|
uri: fullUrl,
|
|
294
610
|
headers: {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
611
|
+
Authorization: `Bearer ${bearerToken}`,
|
|
612
|
+
"X-API-DOMAIN": apiDomain,
|
|
613
|
+
"X-APIKEY-TOKEN": apiKeyToken,
|
|
614
|
+
"Content-Type": "application/json",
|
|
299
615
|
},
|
|
300
616
|
json: true,
|
|
301
617
|
};
|
|
302
|
-
if (method !==
|
|
618
|
+
if (method !== "GET" &&
|
|
619
|
+
method !== "DELETE" &&
|
|
620
|
+
Object.keys(body).length > 0) {
|
|
303
621
|
options.body = body;
|
|
304
622
|
}
|
|
305
623
|
const responseData = await this.helpers.request(options);
|
|
306
624
|
returnData.push({
|
|
307
625
|
json: {
|
|
308
626
|
success: true,
|
|
627
|
+
normalized: {
|
|
628
|
+
originalResource: this.getNodeParameter("resource", i, ""),
|
|
629
|
+
originalOperation: this.getNodeParameter("operation", i, ""),
|
|
630
|
+
normalizedResource: resource,
|
|
631
|
+
normalizedOperation: operation,
|
|
632
|
+
},
|
|
309
633
|
operation,
|
|
310
634
|
resource,
|
|
311
635
|
endpoint,
|
|
@@ -323,7 +647,7 @@ class Confirm8AgentTool {
|
|
|
323
647
|
returnData.push({
|
|
324
648
|
json: {
|
|
325
649
|
success: false,
|
|
326
|
-
error: error.message ||
|
|
650
|
+
error: error.message || "Unknown error",
|
|
327
651
|
},
|
|
328
652
|
pairedItem: { item: i },
|
|
329
653
|
});
|