n8n-nodes-confirm8 0.31.0 → 0.45.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,10 +1,9 @@
|
|
|
1
|
-
import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription
|
|
1
|
+
import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
|
|
2
2
|
export declare class Confirm8AgentTool implements INodeType {
|
|
3
3
|
description: INodeTypeDescription;
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
* This helps the AI understand when and how to use this tool
|
|
5
|
+
* Parse natural date queries into filter JSON
|
|
7
6
|
*/
|
|
8
|
-
|
|
7
|
+
private parseDateQuery;
|
|
9
8
|
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
10
9
|
}
|
|
@@ -10,11 +10,10 @@ class Confirm8AgentTool {
|
|
|
10
10
|
icon: 'file:tool.svg',
|
|
11
11
|
group: ['transform'],
|
|
12
12
|
version: 1,
|
|
13
|
-
description: 'AI
|
|
13
|
+
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
14
|
defaults: {
|
|
15
15
|
name: 'Confirm8 AI Tool',
|
|
16
16
|
},
|
|
17
|
-
// IMPORTANT: Makes this node usable as an AI Agent Tool
|
|
18
17
|
usableAsTool: true,
|
|
19
18
|
inputs: ['main'],
|
|
20
19
|
outputs: ['main'],
|
|
@@ -27,7 +26,6 @@ class Confirm8AgentTool {
|
|
|
27
26
|
default: '',
|
|
28
27
|
placeholder: 'https://api.confirm8.com',
|
|
29
28
|
required: true,
|
|
30
|
-
description: 'Base URL of Confirm8 API',
|
|
31
29
|
},
|
|
32
30
|
{
|
|
33
31
|
displayName: 'Bearer Token',
|
|
@@ -36,7 +34,6 @@ class Confirm8AgentTool {
|
|
|
36
34
|
typeOptions: { password: true },
|
|
37
35
|
default: '',
|
|
38
36
|
required: true,
|
|
39
|
-
description: 'Authentication token',
|
|
40
37
|
},
|
|
41
38
|
{
|
|
42
39
|
displayName: 'X-API-DOMAIN',
|
|
@@ -53,247 +50,379 @@ class Confirm8AgentTool {
|
|
|
53
50
|
default: '',
|
|
54
51
|
required: true,
|
|
55
52
|
},
|
|
56
|
-
//
|
|
53
|
+
// Tool parameters
|
|
57
54
|
{
|
|
58
55
|
displayName: 'Resource',
|
|
59
56
|
name: 'resource',
|
|
60
57
|
type: 'options',
|
|
61
|
-
noDataExpression: true,
|
|
62
58
|
options: [
|
|
63
|
-
{ name: 'User', value: 'user', description: '
|
|
64
|
-
{ name: 'Client', value: 'client', description: '
|
|
65
|
-
{ name: 'Item', value: 'item', description: '
|
|
66
|
-
{ name: '
|
|
67
|
-
{ name: '
|
|
68
|
-
{ name: '
|
|
69
|
-
{ name: '
|
|
70
|
-
{ name: '
|
|
71
|
-
{ name: '
|
|
59
|
+
{ name: 'User', value: 'user', description: 'Users/Employees/Funcionários' },
|
|
60
|
+
{ name: 'Client', value: 'client', description: 'Clients/Customers/Clientes' },
|
|
61
|
+
{ name: 'Item', value: 'item', description: 'Items/Itens' },
|
|
62
|
+
{ name: 'Item Type', value: 'itemType', description: 'Item Types/Tipos' },
|
|
63
|
+
{ name: 'Task', value: 'task', description: 'Tasks/Tarefas/Checklists' },
|
|
64
|
+
{ name: 'Service', value: 'service', description: 'Services/Serviços' },
|
|
65
|
+
{ name: 'Product', value: 'product', description: 'Products/Produtos' },
|
|
66
|
+
{ name: 'Order (OS)', value: 'order', description: 'Work Orders/OS/Ordens de Serviço/WOS' },
|
|
67
|
+
{ name: 'Modality', value: 'modality', description: 'Modalities/Modalidades' },
|
|
68
|
+
{ name: 'Ticket', value: 'ticket', description: 'Tickets/Chamados' },
|
|
69
|
+
{ name: 'Property', value: 'property', description: 'Properties/Propriedades' },
|
|
72
70
|
],
|
|
73
71
|
default: 'user',
|
|
74
|
-
description: '
|
|
72
|
+
description: 'CRITICAL: For "OS" or "ordem de serviço" ALWAYS use "order"',
|
|
75
73
|
},
|
|
76
74
|
{
|
|
77
75
|
displayName: 'Operation',
|
|
78
76
|
name: 'operation',
|
|
79
77
|
type: 'options',
|
|
80
|
-
noDataExpression: true,
|
|
81
78
|
options: [
|
|
82
|
-
{
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
name: 'Get All',
|
|
89
|
-
value: 'getAll',
|
|
90
|
-
description: 'Fetch all records or list records'
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
name: 'Create',
|
|
94
|
-
value: 'create',
|
|
95
|
-
description: 'Create a new record'
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
name: 'Update',
|
|
99
|
-
value: 'update',
|
|
100
|
-
description: 'Update an existing record'
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
name: 'Activate',
|
|
104
|
-
value: 'activate',
|
|
105
|
-
description: 'Activate/enable a record'
|
|
106
|
-
},
|
|
107
|
-
{
|
|
108
|
-
name: 'Deactivate',
|
|
109
|
-
value: 'deactivate',
|
|
110
|
-
description: 'Deactivate/disable a record'
|
|
111
|
-
},
|
|
79
|
+
{ name: 'Get All (List)', value: 'getAll', description: 'List/Listar/Buscar todos/Mostrar todos' },
|
|
80
|
+
{ name: 'Get (Single)', value: 'get', description: 'Get one/Buscar um/Obter' },
|
|
81
|
+
{ name: 'Create', value: 'create', description: 'Create/Criar/Adicionar' },
|
|
82
|
+
{ name: 'Update', value: 'update', description: 'Update/Atualizar/Modificar' },
|
|
83
|
+
{ name: 'Activate', value: 'activate', description: 'Activate/Ativar' },
|
|
84
|
+
{ name: 'Deactivate', value: 'deactivate', description: 'Deactivate/Desativar' },
|
|
112
85
|
],
|
|
113
86
|
default: 'getAll',
|
|
114
|
-
description: '
|
|
87
|
+
description: 'CRITICAL: To list/search use "getAll"',
|
|
115
88
|
},
|
|
116
89
|
{
|
|
117
90
|
displayName: 'Record ID',
|
|
118
91
|
name: 'recordId',
|
|
119
92
|
type: 'string',
|
|
120
93
|
default: '',
|
|
121
|
-
|
|
122
|
-
show: {
|
|
123
|
-
operation: ['get', 'update', 'activate', 'deactivate'],
|
|
124
|
-
},
|
|
125
|
-
},
|
|
126
|
-
description: 'ID of the record to fetch or modify',
|
|
94
|
+
description: 'Record ID (only for get/update/activate/deactivate)',
|
|
127
95
|
},
|
|
128
96
|
{
|
|
129
|
-
displayName: 'Data
|
|
130
|
-
name: '
|
|
131
|
-
type: '
|
|
132
|
-
default: '
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
97
|
+
displayName: 'Data',
|
|
98
|
+
name: 'data',
|
|
99
|
+
type: 'string',
|
|
100
|
+
default: '',
|
|
101
|
+
description: 'JSON data (only for create/update)',
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
displayName: 'Filters',
|
|
105
|
+
name: 'filters',
|
|
106
|
+
type: 'string',
|
|
107
|
+
default: '',
|
|
108
|
+
description: 'Filters as JSON. For dates: {"start_date":{"gte":"YYYY-MM-DD"},"end_date":{"lte":"YYYY-MM-DD"}}. For status: {"status":{"eq":"complete"}}',
|
|
139
109
|
},
|
|
140
110
|
],
|
|
141
111
|
};
|
|
142
112
|
}
|
|
143
113
|
/**
|
|
144
|
-
*
|
|
145
|
-
* This helps the AI understand when and how to use this tool
|
|
114
|
+
* Parse natural date queries into filter JSON
|
|
146
115
|
*/
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
'"Create" to add new records, "Update" to modify existing records, ' +
|
|
155
|
-
'"Activate/Deactivate" to enable or disable records.',
|
|
156
|
-
properties: [
|
|
157
|
-
{
|
|
158
|
-
displayName: 'Resource',
|
|
159
|
-
name: 'resource',
|
|
160
|
-
type: 'options',
|
|
161
|
-
required: true,
|
|
162
|
-
options: [
|
|
163
|
-
{ name: 'User', value: 'user' },
|
|
164
|
-
{ name: 'Client', value: 'client' },
|
|
165
|
-
{ name: 'Item', value: 'item' },
|
|
166
|
-
{ name: 'Task', value: 'task' },
|
|
167
|
-
{ name: 'Service', value: 'service' },
|
|
168
|
-
{ name: 'Product', value: 'product' },
|
|
169
|
-
{ name: 'Order', value: 'order' },
|
|
170
|
-
{ name: 'Ticket', value: 'ticket' },
|
|
171
|
-
{ name: 'Property', value: 'property' },
|
|
172
|
-
],
|
|
173
|
-
description: 'Type of resource: user, client, item, task, service, product, order, ticket, or property',
|
|
174
|
-
},
|
|
175
|
-
{
|
|
176
|
-
displayName: 'Operation',
|
|
177
|
-
name: 'operation',
|
|
178
|
-
type: 'options',
|
|
179
|
-
required: true,
|
|
180
|
-
options: [
|
|
181
|
-
{ name: 'Get', value: 'get' },
|
|
182
|
-
{ name: 'Get All', value: 'getAll' },
|
|
183
|
-
{ name: 'Create', value: 'create' },
|
|
184
|
-
{ name: 'Update', value: 'update' },
|
|
185
|
-
{ name: 'Activate', value: 'activate' },
|
|
186
|
-
{ name: 'Deactivate', value: 'deactivate' },
|
|
187
|
-
],
|
|
188
|
-
description: 'Operation: get (single), getAll (list), create, update, activate, deactivate',
|
|
189
|
-
},
|
|
190
|
-
{
|
|
191
|
-
displayName: 'Record ID',
|
|
192
|
-
name: 'recordId',
|
|
193
|
-
type: 'string',
|
|
194
|
-
required: false,
|
|
195
|
-
description: 'ID of the record (required for get, update, activate, deactivate)',
|
|
196
|
-
},
|
|
197
|
-
{
|
|
198
|
-
displayName: 'Data',
|
|
199
|
-
name: 'dataJson',
|
|
200
|
-
type: 'json',
|
|
201
|
-
required: false,
|
|
202
|
-
description: 'JSON data for create/update operations. Example: {"name":"John","email":"john@example.com"}',
|
|
203
|
-
},
|
|
204
|
-
],
|
|
116
|
+
parseDateQuery(query) {
|
|
117
|
+
const now = new Date();
|
|
118
|
+
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
119
|
+
query = query.toLowerCase().trim();
|
|
120
|
+
// Helper to format date as YYYY-MM-DD
|
|
121
|
+
const formatDate = (date) => {
|
|
122
|
+
return date.toISOString().split('T')[0];
|
|
205
123
|
};
|
|
124
|
+
// Today
|
|
125
|
+
if (query.includes('hoje') || query.includes('today')) {
|
|
126
|
+
const endOfDay = new Date(today);
|
|
127
|
+
endOfDay.setHours(23, 59, 59, 999);
|
|
128
|
+
return {
|
|
129
|
+
start_date: { gte: formatDate(today) },
|
|
130
|
+
end_date: { lte: formatDate(endOfDay) }
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
// This week / semana atual
|
|
134
|
+
if (query.includes('semana') || query.includes('week')) {
|
|
135
|
+
const dayOfWeek = today.getDay();
|
|
136
|
+
const diff = dayOfWeek === 0 ? -6 : 1 - dayOfWeek; // Monday is start
|
|
137
|
+
const weekStart = new Date(today);
|
|
138
|
+
weekStart.setDate(today.getDate() + diff);
|
|
139
|
+
const weekEnd = new Date(weekStart);
|
|
140
|
+
weekEnd.setDate(weekStart.getDate() + 6);
|
|
141
|
+
return {
|
|
142
|
+
start_date: { gte: formatDate(weekStart) },
|
|
143
|
+
end_date: { lte: formatDate(weekEnd) }
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
// This month / mês atual
|
|
147
|
+
if (query.includes('mês') || query.includes('mes') || query.includes('month')) {
|
|
148
|
+
const monthStart = new Date(now.getFullYear(), now.getMonth(), 1);
|
|
149
|
+
const monthEnd = new Date(now.getFullYear(), now.getMonth() + 1, 0);
|
|
150
|
+
return {
|
|
151
|
+
start_date: { gte: formatDate(monthStart) },
|
|
152
|
+
end_date: { lte: formatDate(monthEnd) }
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
// Last N days
|
|
156
|
+
const lastDaysMatch = query.match(/últimos?\s+(\d+)\s+dias?|last\s+(\d+)\s+days?/);
|
|
157
|
+
if (lastDaysMatch) {
|
|
158
|
+
const days = parseInt(lastDaysMatch[1] || lastDaysMatch[2]);
|
|
159
|
+
const startDate = new Date(today);
|
|
160
|
+
startDate.setDate(today.getDate() - days);
|
|
161
|
+
return {
|
|
162
|
+
start_date: { gte: formatDate(startDate) },
|
|
163
|
+
end_date: { lte: formatDate(today) }
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
// Next N days
|
|
167
|
+
const nextDaysMatch = query.match(/próximos?\s+(\d+)\s+dias?|next\s+(\d+)\s+days?/);
|
|
168
|
+
if (nextDaysMatch) {
|
|
169
|
+
const days = parseInt(nextDaysMatch[1] || nextDaysMatch[2]);
|
|
170
|
+
const endDate = new Date(today);
|
|
171
|
+
endDate.setDate(today.getDate() + days);
|
|
172
|
+
return {
|
|
173
|
+
start_date: { gte: formatDate(today) },
|
|
174
|
+
end_date: { lte: formatDate(endDate) }
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
return null;
|
|
206
178
|
}
|
|
207
179
|
async execute() {
|
|
208
180
|
const items = this.getInputData();
|
|
209
181
|
const returnData = [];
|
|
210
182
|
for (let i = 0; i < items.length; i++) {
|
|
211
183
|
try {
|
|
212
|
-
// Get API configuration
|
|
213
184
|
const baseUrl = this.getNodeParameter('baseUrl', i);
|
|
214
185
|
const bearerToken = this.getNodeParameter('bearerToken', i);
|
|
215
186
|
const apiDomain = this.getNodeParameter('apiDomain', i);
|
|
216
187
|
const apiKeyToken = this.getNodeParameter('apiKeyToken', i);
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
const operation = this.getNodeParameter('operation', i);
|
|
188
|
+
let resource = this.getNodeParameter('resource', i, '');
|
|
189
|
+
let operation = this.getNodeParameter('operation', i, '');
|
|
220
190
|
const recordId = this.getNodeParameter('recordId', i, '');
|
|
221
|
-
// Parse data
|
|
222
|
-
let
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
191
|
+
// Parse data
|
|
192
|
+
let data = {};
|
|
193
|
+
const dataParam = this.getNodeParameter('data', i, '');
|
|
194
|
+
if (dataParam) {
|
|
195
|
+
try {
|
|
196
|
+
data = JSON.parse(dataParam);
|
|
197
|
+
}
|
|
198
|
+
catch (e) {
|
|
199
|
+
// Ignore
|
|
227
200
|
}
|
|
228
201
|
}
|
|
229
|
-
|
|
230
|
-
|
|
202
|
+
// Parse filters
|
|
203
|
+
let filters = {};
|
|
204
|
+
const filtersParam = this.getNodeParameter('filters', i, '');
|
|
205
|
+
if (filtersParam) {
|
|
206
|
+
try {
|
|
207
|
+
// Try to parse as JSON first
|
|
208
|
+
filters = JSON.parse(filtersParam);
|
|
209
|
+
}
|
|
210
|
+
catch (e) {
|
|
211
|
+
// If not JSON, try to parse as natural language date query
|
|
212
|
+
const parsedDate = this.parseDateQuery(filtersParam);
|
|
213
|
+
if (parsedDate) {
|
|
214
|
+
filters = parsedDate;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
231
217
|
}
|
|
232
|
-
//
|
|
218
|
+
// Aggressive normalization - EXPAND THIS
|
|
233
219
|
const resourceMap = {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
220
|
+
// Standard
|
|
221
|
+
'users': 'user', 'usuarios': 'user', 'usuários': 'user', 'employees': 'user', 'funcionários': 'user', 'funcionarios': 'user',
|
|
222
|
+
'clients': 'client', 'clientes': 'client', 'customers': 'client',
|
|
223
|
+
'items': 'item', 'itens': 'item',
|
|
224
|
+
'itemtypes': 'itemType', 'tipos': 'itemType',
|
|
225
|
+
'tasks': 'task', 'tarefas': 'task',
|
|
226
|
+
'services': 'service', 'serviços': 'service', 'servicos': 'service',
|
|
227
|
+
'products': 'product', 'produtos': 'product',
|
|
228
|
+
'modalities': 'modality', 'modalidades': 'modality',
|
|
229
|
+
'tickets': 'ticket', 'chamados': 'ticket',
|
|
230
|
+
'properties': 'property', 'propriedades': 'property',
|
|
231
|
+
// CRITICAL: OS mappings
|
|
232
|
+
'os': 'order',
|
|
233
|
+
'o.s': 'order',
|
|
234
|
+
'o.s.': 'order',
|
|
235
|
+
'orders': 'order',
|
|
236
|
+
'ordens': 'order',
|
|
237
|
+
'ordem': 'order',
|
|
238
|
+
'ordem de serviço': 'order',
|
|
239
|
+
'ordem de servico': 'order',
|
|
240
|
+
'ordens de serviço': 'order',
|
|
241
|
+
'ordens de servico': 'order',
|
|
242
|
+
'wos': 'order',
|
|
243
|
+
'work order': 'order',
|
|
244
|
+
'work orders': 'order',
|
|
245
|
+
'pedidos': 'order',
|
|
246
|
+
'pedido': 'order',
|
|
247
|
+
};
|
|
248
|
+
const operationMap = {
|
|
249
|
+
// List/Get All
|
|
250
|
+
'list': 'getAll',
|
|
251
|
+
'listar': 'getAll',
|
|
252
|
+
'mostrar': 'getAll',
|
|
253
|
+
'buscar': 'getAll',
|
|
254
|
+
'busque': 'getAll',
|
|
255
|
+
'buscar todos': 'getAll',
|
|
256
|
+
'buscar todas': 'getAll',
|
|
257
|
+
'buscar todo': 'getAll',
|
|
258
|
+
'buscar toda': 'getAll',
|
|
259
|
+
'get all': 'getAll',
|
|
260
|
+
'show all': 'getAll',
|
|
261
|
+
'list all': 'getAll',
|
|
262
|
+
'todos': 'getAll',
|
|
263
|
+
'todas': 'getAll',
|
|
264
|
+
'obter todos': 'getAll',
|
|
265
|
+
'obter todas': 'getAll',
|
|
266
|
+
'pegar todos': 'getAll',
|
|
267
|
+
'pegar todas': 'getAll',
|
|
268
|
+
// Get Single
|
|
269
|
+
'obter': 'get',
|
|
270
|
+
'pegar': 'get',
|
|
271
|
+
'ver': 'get',
|
|
272
|
+
'visualizar': 'get',
|
|
273
|
+
// Create
|
|
274
|
+
'criar': 'create',
|
|
275
|
+
'adicionar': 'create',
|
|
276
|
+
'add': 'create',
|
|
277
|
+
'novo': 'create',
|
|
278
|
+
'nova': 'create',
|
|
279
|
+
'new': 'create',
|
|
280
|
+
// Update
|
|
281
|
+
'atualizar': 'update',
|
|
282
|
+
'modificar': 'update',
|
|
283
|
+
'modify': 'update',
|
|
284
|
+
'editar': 'update',
|
|
285
|
+
'edit': 'update',
|
|
286
|
+
// Activate/Deactivate
|
|
287
|
+
'ativar': 'activate',
|
|
288
|
+
'enable': 'activate',
|
|
289
|
+
'habilitar': 'activate',
|
|
290
|
+
'desativar': 'deactivate',
|
|
291
|
+
'disable': 'deactivate',
|
|
292
|
+
'desabilitar': 'deactivate',
|
|
293
|
+
};
|
|
294
|
+
// Normalize - clean and map
|
|
295
|
+
const cleanResource = resource.toLowerCase().trim().replace(/\s+/g, ' ');
|
|
296
|
+
const cleanOperation = operation.toLowerCase().trim().replace(/\s+/g, ' ');
|
|
297
|
+
resource = resourceMap[cleanResource] || resource;
|
|
298
|
+
operation = operationMap[cleanOperation] || operation;
|
|
299
|
+
// If still not valid, throw clear error
|
|
300
|
+
const validResources = ['user', 'client', 'item', 'itemType', 'task', 'service', 'product', 'order', 'modality', 'ticket', 'property'];
|
|
301
|
+
const validOperations = ['getAll', 'get', 'create', 'update', 'activate', 'deactivate'];
|
|
302
|
+
if (!validResources.includes(resource)) {
|
|
303
|
+
throw new Error(`Invalid resource: "${resource}". Must be one of: ${validResources.join(', ')}. ` +
|
|
304
|
+
`For OS/Ordem de Serviço use "order".`);
|
|
305
|
+
}
|
|
306
|
+
if (!validOperations.includes(operation)) {
|
|
307
|
+
throw new Error(`Invalid operation: "${operation}". Must be one of: ${validOperations.join(', ')}. ` +
|
|
308
|
+
`To list/search use "getAll".`);
|
|
309
|
+
}
|
|
310
|
+
// Resource config with relations
|
|
311
|
+
const resourceConfig = {
|
|
312
|
+
user: {
|
|
313
|
+
endpoint: 'users',
|
|
314
|
+
relations: ['clients', 'attachments', 'permissions', 'device', 'employee']
|
|
315
|
+
},
|
|
316
|
+
client: {
|
|
317
|
+
endpoint: 'clients',
|
|
318
|
+
relations: ['wos', 'items', 'employees', 'headquarter', 'files', 'userGroup', 'properties']
|
|
319
|
+
},
|
|
320
|
+
item: {
|
|
321
|
+
endpoint: 'items',
|
|
322
|
+
relations: ['client', 'item_type', 'properties', 'parent', 'children', 'collects', 'wos']
|
|
323
|
+
},
|
|
324
|
+
itemType: {
|
|
325
|
+
endpoint: 'itemTypes',
|
|
326
|
+
relations: ['properties']
|
|
327
|
+
},
|
|
328
|
+
task: {
|
|
329
|
+
endpoint: 'tasks',
|
|
330
|
+
relations: ['itemType', 'activities', 'wos', 'modalities']
|
|
331
|
+
},
|
|
332
|
+
service: {
|
|
333
|
+
endpoint: 'services',
|
|
334
|
+
relations: ['task']
|
|
335
|
+
},
|
|
336
|
+
product: {
|
|
337
|
+
endpoint: 'products',
|
|
338
|
+
relations: []
|
|
339
|
+
},
|
|
340
|
+
order: {
|
|
341
|
+
endpoint: 'wos',
|
|
342
|
+
relations: ['client', 'modalities', 'tasks', 'pivot_tasks', 'products', 'users', 'items', 'tickets', 'services', 'collects', 'attachments']
|
|
343
|
+
},
|
|
344
|
+
modality: {
|
|
345
|
+
endpoint: 'modalities',
|
|
346
|
+
relations: ['tasks']
|
|
347
|
+
},
|
|
348
|
+
ticket: {
|
|
349
|
+
endpoint: 'tickets',
|
|
350
|
+
relations: ['client', 'subject_category', 'category', 'status', 'attachments', 'item', 'owner', 'priority', 'users', 'orders', 'properties']
|
|
351
|
+
},
|
|
352
|
+
property: {
|
|
353
|
+
endpoint: 'properties',
|
|
354
|
+
relations: []
|
|
355
|
+
},
|
|
243
356
|
};
|
|
244
|
-
const
|
|
245
|
-
|
|
357
|
+
const config = resourceConfig[resource];
|
|
358
|
+
const baseEndpoint = config.endpoint;
|
|
359
|
+
let endpoint = '';
|
|
246
360
|
let method = 'GET';
|
|
247
361
|
let body = {};
|
|
248
|
-
// Build
|
|
362
|
+
// Build endpoint
|
|
249
363
|
switch (operation) {
|
|
250
364
|
case 'getAll':
|
|
251
|
-
|
|
252
|
-
method = 'GET';
|
|
365
|
+
endpoint = `/v3/${baseEndpoint}`;
|
|
253
366
|
break;
|
|
254
367
|
case 'get':
|
|
255
|
-
if (!recordId)
|
|
256
|
-
throw new Error('
|
|
257
|
-
}
|
|
258
|
-
url = `${baseUrl}/${endpoint}/${recordId}`;
|
|
259
|
-
method = 'GET';
|
|
368
|
+
if (!recordId)
|
|
369
|
+
throw new Error('recordId required');
|
|
370
|
+
endpoint = `/v3/${baseEndpoint}/${recordId}`;
|
|
260
371
|
break;
|
|
261
372
|
case 'create':
|
|
262
|
-
|
|
373
|
+
endpoint = `/v3/${baseEndpoint}`;
|
|
263
374
|
method = 'POST';
|
|
264
|
-
body =
|
|
375
|
+
body = data;
|
|
265
376
|
break;
|
|
266
377
|
case 'update':
|
|
267
|
-
if (!recordId)
|
|
268
|
-
throw new Error('
|
|
269
|
-
}
|
|
270
|
-
url = `${baseUrl}/${endpoint}/${recordId}`;
|
|
378
|
+
if (!recordId)
|
|
379
|
+
throw new Error('recordId required');
|
|
380
|
+
endpoint = `/v3/${baseEndpoint}/${recordId}`;
|
|
271
381
|
method = 'PUT';
|
|
272
|
-
body =
|
|
382
|
+
body = data;
|
|
273
383
|
break;
|
|
274
384
|
case 'activate':
|
|
275
|
-
if (!recordId)
|
|
276
|
-
throw new Error('
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
resource === 'service' || resource === 'product' || resource === 'order' ? 'PUT' : 'PATCH';
|
|
385
|
+
if (!recordId)
|
|
386
|
+
throw new Error('recordId required');
|
|
387
|
+
endpoint = `/v3/${baseEndpoint}/${recordId}/active`;
|
|
388
|
+
method = ['client', 'item', 'itemType', 'task', 'service', 'product', 'order', 'modality'].includes(resource)
|
|
389
|
+
? 'PUT' : 'PATCH';
|
|
281
390
|
break;
|
|
282
391
|
case 'deactivate':
|
|
283
|
-
if (!recordId)
|
|
284
|
-
throw new Error('
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
resource === 'service' || resource === 'product' || resource === 'order' ? 'PUT' : 'PATCH';
|
|
392
|
+
if (!recordId)
|
|
393
|
+
throw new Error('recordId required');
|
|
394
|
+
endpoint = `/v3/${baseEndpoint}/${recordId}/inactive`;
|
|
395
|
+
method = ['client', 'item', 'itemType', 'task', 'service', 'product', 'order', 'modality'].includes(resource)
|
|
396
|
+
? 'PUT' : 'PATCH';
|
|
289
397
|
break;
|
|
290
|
-
default:
|
|
291
|
-
throw new Error(`Unknown operation: ${operation}`);
|
|
292
398
|
}
|
|
293
|
-
//
|
|
399
|
+
// Build query string
|
|
400
|
+
const queryParams = [];
|
|
401
|
+
// Add relations (only GET)
|
|
402
|
+
if (method === 'GET' && config.relations.length > 0) {
|
|
403
|
+
config.relations.forEach(relation => {
|
|
404
|
+
queryParams.push(`relations=${relation}`);
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
// Add filters
|
|
408
|
+
if (Object.keys(filters).length > 0) {
|
|
409
|
+
Object.keys(filters).forEach(field => {
|
|
410
|
+
const operators = filters[field];
|
|
411
|
+
Object.keys(operators).forEach(operator => {
|
|
412
|
+
const value = operators[operator];
|
|
413
|
+
queryParams.push(`filters[${field}][${operator}]=${encodeURIComponent(String(value))}`);
|
|
414
|
+
});
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
// Full URL
|
|
418
|
+
let fullUrl = `${baseUrl}${endpoint}`;
|
|
419
|
+
if (queryParams.length > 0) {
|
|
420
|
+
fullUrl += '?' + queryParams.join('&');
|
|
421
|
+
}
|
|
422
|
+
// Make request
|
|
294
423
|
const options = {
|
|
295
424
|
method,
|
|
296
|
-
uri:
|
|
425
|
+
uri: fullUrl,
|
|
297
426
|
headers: {
|
|
298
427
|
'Authorization': `Bearer ${bearerToken}`,
|
|
299
428
|
'X-API-DOMAIN': apiDomain,
|
|
@@ -309,8 +438,19 @@ class Confirm8AgentTool {
|
|
|
309
438
|
returnData.push({
|
|
310
439
|
json: {
|
|
311
440
|
success: true,
|
|
441
|
+
normalized: {
|
|
442
|
+
originalResource: this.getNodeParameter('resource', i, ''),
|
|
443
|
+
originalOperation: this.getNodeParameter('operation', i, ''),
|
|
444
|
+
normalizedResource: resource,
|
|
445
|
+
normalizedOperation: operation,
|
|
446
|
+
},
|
|
312
447
|
operation,
|
|
313
448
|
resource,
|
|
449
|
+
endpoint,
|
|
450
|
+
fullUrl,
|
|
451
|
+
relations: config.relations,
|
|
452
|
+
filters: filters,
|
|
453
|
+
method,
|
|
314
454
|
data: responseData,
|
|
315
455
|
},
|
|
316
456
|
pairedItem: { item: i },
|
|
@@ -321,7 +461,7 @@ class Confirm8AgentTool {
|
|
|
321
461
|
returnData.push({
|
|
322
462
|
json: {
|
|
323
463
|
success: false,
|
|
324
|
-
error: error || 'Unknown error',
|
|
464
|
+
error: error.message || 'Unknown error',
|
|
325
465
|
},
|
|
326
466
|
pairedItem: { item: i },
|
|
327
467
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n8n-nodes-confirm8",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.45.0",
|
|
4
4
|
"description": "Simple n8n node for Confirm8 API - no credentials needed",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Bill Hebert",
|
|
@@ -21,8 +21,7 @@
|
|
|
21
21
|
},
|
|
22
22
|
"n8n": {
|
|
23
23
|
"nodes": [
|
|
24
|
-
"dist/nodes/Confirm8/ApiConfirm8.node.js"
|
|
25
|
-
"dist/nodes/Confirm8Tool/Confirm8AgentTool.node.js"
|
|
24
|
+
"dist/nodes/Confirm8/ApiConfirm8.node.js"
|
|
26
25
|
]
|
|
27
26
|
},
|
|
28
27
|
"peerDependencies": {
|