@limetech/n8n-nodes-lime 0.2.8 → 0.3.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.
- package/.dockerignore +1 -0
- package/.github/workflows/lint.yml +21 -0
- package/.github/workflows/release.yml +82 -0
- package/.github/workflows/test-and-build.yml +47 -0
- package/.prettierignore +4 -0
- package/.prettierrc.mjs +1 -0
- package/.releaserc.json +34 -0
- package/CHANGELOG.md +74 -0
- package/Dockerfile +21 -0
- package/README.md +4 -0
- package/credentials/FortnoxApi.credentials.ts +61 -0
- package/credentials/LimeCrmApi.credentials.ts +60 -0
- package/dist/nodes/LimeCrm/resources/limeObject/operations/update.operation.js +1 -1
- package/dist/nodes/LimeCrm/resources/limeObject/operations/update.operation.js.map +1 -1
- package/dist/package.json +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/docker-compose.yml +46 -0
- package/eslint.config.mjs +27 -0
- package/jest.config.js +11 -0
- package/nodes/fortnox/Fortnox.node.json +18 -0
- package/nodes/fortnox/Fortnox.node.ts +102 -0
- package/nodes/fortnox/FortnoxTrigger.node.json +18 -0
- package/nodes/fortnox/FortnoxTrigger.node.ts +196 -0
- package/nodes/fortnox/commons.ts +94 -0
- package/nodes/fortnox/fortnoxLogo.svg +15 -0
- package/nodes/fortnox/model.ts +25 -0
- package/nodes/fortnox/resources/customers/filterParameters.ts +47 -0
- package/nodes/fortnox/resources/customers/index.ts +57 -0
- package/nodes/fortnox/resources/customers/model.ts +107 -0
- package/nodes/fortnox/resources/customers/operations/create.operation.ts +303 -0
- package/nodes/fortnox/resources/customers/operations/delete.operation.ts +44 -0
- package/nodes/fortnox/resources/customers/operations/get.operation.ts +45 -0
- package/nodes/fortnox/resources/customers/operations/getAll.operation.ts +80 -0
- package/nodes/fortnox/resources/customers/operations/update.operation.ts +278 -0
- package/nodes/fortnox/resources/customers/sortParameters.ts +32 -0
- package/nodes/fortnox/resources/invoice/filterParameters.ts +88 -0
- package/nodes/fortnox/resources/invoice/index.ts +51 -0
- package/nodes/fortnox/resources/invoice/invoiceParameters.ts +214 -0
- package/nodes/fortnox/resources/invoice/model.ts +160 -0
- package/nodes/fortnox/resources/invoice/operations/create.operation.ts +72 -0
- package/nodes/fortnox/resources/invoice/operations/get.operation.ts +45 -0
- package/nodes/fortnox/resources/invoice/operations/getAll.operation.ts +101 -0
- package/nodes/fortnox/resources/invoice/operations/update.operation.ts +74 -0
- package/nodes/fortnox/transport/errorCodes.ts +62 -0
- package/nodes/fortnox/transport/index.ts +98 -0
- package/nodes/lime-crm/LimeCrm.node.json +18 -0
- package/nodes/lime-crm/LimeCrmNode.node.ts +135 -0
- package/nodes/lime-crm/LimeCrmTrigger.node.ts +263 -0
- package/nodes/lime-crm/assets/lime-crm.svg +1 -0
- package/nodes/lime-crm/commons/constants.ts +9 -0
- package/nodes/lime-crm/commons/index.ts +9 -0
- package/nodes/lime-crm/commons/limetype.ts +11 -0
- package/nodes/lime-crm/commons/task.ts +55 -0
- package/nodes/lime-crm/commons/webhook.ts +50 -0
- package/nodes/lime-crm/methods/getEntitiesForErpSystem.ts +11 -0
- package/nodes/lime-crm/methods/getLimeTypeProperties.ts +27 -0
- package/nodes/lime-crm/methods/getLimeTypes.ts +23 -0
- package/nodes/lime-crm/methods/index.ts +3 -0
- package/nodes/lime-crm/resources/erpConnector/index.ts +43 -0
- package/nodes/lime-crm/resources/erpConnector/operations/createOrUpdateObjects.operation.ts +69 -0
- package/nodes/lime-crm/resources/erpConnector/operations/transform.operation.ts +274 -0
- package/nodes/lime-crm/resources/erpConnector/transform.ts +49 -0
- package/nodes/lime-crm/resources/erpConnector/transformers/baseTransformer.ts +18 -0
- package/nodes/lime-crm/resources/erpConnector/transformers/fortnox.ts +201 -0
- package/nodes/lime-crm/resources/erpConnector/transformers/index.ts +1 -0
- package/nodes/lime-crm/resources/limeObject/index.ts +64 -0
- package/nodes/lime-crm/resources/limeObject/operations/create.operation.ts +152 -0
- package/nodes/lime-crm/resources/limeObject/operations/delete.operation.ts +55 -0
- package/nodes/lime-crm/resources/limeObject/operations/get.operation.ts +54 -0
- package/nodes/lime-crm/resources/limeObject/operations/search.operation.ts +99 -0
- package/nodes/lime-crm/resources/limeObject/operations/update.operation.ts +157 -0
- package/nodes/lime-crm/resources/limeType/index.ts +58 -0
- package/nodes/lime-crm/resources/limeType/operations/getProperties.operation.ts +42 -0
- package/nodes/lime-crm/resources/limeType/operations/getType.operation.ts +36 -0
- package/nodes/lime-crm/resources/limeType/operations/listTypes.operation.ts +18 -0
- package/nodes/lime-crm/transport/commons.ts +44 -0
- package/nodes/lime-crm/transport/erpConnector.ts +21 -0
- package/nodes/lime-crm/transport/index.ts +17 -0
- package/nodes/lime-crm/transport/limeobjects.ts +83 -0
- package/nodes/lime-crm/transport/limetypes.ts +68 -0
- package/nodes/lime-crm/transport/task.ts +32 -0
- package/nodes/lime-crm/transport/webhooks.ts +61 -0
- package/nodes/nodeResponse.ts +13 -0
- package/package.json +36 -16
- package/tests/fixtures/fortnox.ts +182 -0
- package/tests/transform.spec.ts +187 -0
- package/tsconfig.json +30 -0
- package/index.js +0 -3
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IExecuteFunctions,
|
|
3
|
+
INodeExecutionData,
|
|
4
|
+
INodeProperties,
|
|
5
|
+
INodeType,
|
|
6
|
+
INodeTypeDescription,
|
|
7
|
+
NodeConnectionType,
|
|
8
|
+
NodePropertyTypes,
|
|
9
|
+
} from 'n8n-workflow';
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
erpConnectorFields,
|
|
13
|
+
erpConnectorOperations,
|
|
14
|
+
} from './resources/erpConnector';
|
|
15
|
+
import { limeTypeFields, limeTypeOperations } from './resources/limeType';
|
|
16
|
+
import { limeObjectFields, limeObjectOperations } from './resources/limeObject';
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
LIMEOBJECT_RESOURCE,
|
|
20
|
+
LIMETYPE_RESOURCE,
|
|
21
|
+
LIME_CRM_API_CREDENTIAL_KEY,
|
|
22
|
+
ERP_CONNECTOR_RESOURCE,
|
|
23
|
+
} from './commons';
|
|
24
|
+
|
|
25
|
+
import {
|
|
26
|
+
getEntitiesForErpSystem,
|
|
27
|
+
getLimeTypeProperties,
|
|
28
|
+
getLimeTypes,
|
|
29
|
+
} from './methods';
|
|
30
|
+
|
|
31
|
+
export class LimeCrmNode implements INodeType {
|
|
32
|
+
description: INodeTypeDescription = {
|
|
33
|
+
displayName: 'Lime CRM',
|
|
34
|
+
name: 'limeCrm',
|
|
35
|
+
icon: 'file:assets/lime-crm.svg',
|
|
36
|
+
group: ['transform'],
|
|
37
|
+
version: 1,
|
|
38
|
+
subtitle:
|
|
39
|
+
'={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
|
40
|
+
description: 'Consume the Lime CRM API',
|
|
41
|
+
defaults: {
|
|
42
|
+
name: 'Lime CRM',
|
|
43
|
+
},
|
|
44
|
+
inputs: [NodeConnectionType.Main],
|
|
45
|
+
outputs: [NodeConnectionType.Main],
|
|
46
|
+
credentials: [
|
|
47
|
+
{
|
|
48
|
+
name: LIME_CRM_API_CREDENTIAL_KEY,
|
|
49
|
+
required: true,
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
properties: [
|
|
53
|
+
{
|
|
54
|
+
displayName: 'Resource',
|
|
55
|
+
name: 'resource',
|
|
56
|
+
type: 'options' as NodePropertyTypes,
|
|
57
|
+
noDataExpression: true,
|
|
58
|
+
options: [
|
|
59
|
+
{
|
|
60
|
+
name: 'Lime Type',
|
|
61
|
+
value: LIMETYPE_RESOURCE,
|
|
62
|
+
description: 'Work with entity type definitions',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: 'Lime Object',
|
|
66
|
+
value: LIMEOBJECT_RESOURCE,
|
|
67
|
+
description: 'Work with actual data records',
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: 'ERP Connector',
|
|
71
|
+
value: ERP_CONNECTOR_RESOURCE,
|
|
72
|
+
description: 'Integrate data between ERP and Lime CRM',
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
default: LIMEOBJECT_RESOURCE,
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
...(limeTypeFields as INodeProperties[]),
|
|
79
|
+
...(limeObjectFields as INodeProperties[]),
|
|
80
|
+
...(erpConnectorFields as INodeProperties[]),
|
|
81
|
+
],
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
methods = {
|
|
85
|
+
loadOptions: {
|
|
86
|
+
getEntitiesForErpSystem,
|
|
87
|
+
getLimeTypes,
|
|
88
|
+
getLimeTypeProperties,
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
|
93
|
+
const items = this.getInputData();
|
|
94
|
+
const returnData = [];
|
|
95
|
+
|
|
96
|
+
const resource = this.getNodeParameter('resource', 0) as string;
|
|
97
|
+
const operation = this.getNodeParameter('operation', 0) as string;
|
|
98
|
+
|
|
99
|
+
for (let i = 0; i < items.length; i++) {
|
|
100
|
+
let responseData;
|
|
101
|
+
try {
|
|
102
|
+
if (resource === LIMETYPE_RESOURCE) {
|
|
103
|
+
responseData = await limeTypeOperations.call(this, {
|
|
104
|
+
operation,
|
|
105
|
+
i,
|
|
106
|
+
});
|
|
107
|
+
} else if (resource === LIMEOBJECT_RESOURCE) {
|
|
108
|
+
responseData = await limeObjectOperations.call(this, {
|
|
109
|
+
operation,
|
|
110
|
+
i,
|
|
111
|
+
});
|
|
112
|
+
} else if (resource === ERP_CONNECTOR_RESOURCE) {
|
|
113
|
+
responseData = await erpConnectorOperations.call(this, {
|
|
114
|
+
operation,
|
|
115
|
+
i,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
returnData.push({ json: responseData });
|
|
120
|
+
} catch (error) {
|
|
121
|
+
if (this.continueOnFail()) {
|
|
122
|
+
returnData.push({
|
|
123
|
+
error: error.message,
|
|
124
|
+
json: { error: error.message },
|
|
125
|
+
});
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
throw error;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return [this.helpers.returnJsonArray(returnData)];
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export { LimeCrmTrigger } from './LimeCrmTrigger.node';
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IHookFunctions,
|
|
3
|
+
IWebhookFunctions,
|
|
4
|
+
IDataObject,
|
|
5
|
+
INodeType,
|
|
6
|
+
INodeTypeDescription,
|
|
7
|
+
IWebhookResponseData,
|
|
8
|
+
NodeOperationError,
|
|
9
|
+
LoggerProxy as Logger,
|
|
10
|
+
NodeConnectionType,
|
|
11
|
+
} from 'n8n-workflow';
|
|
12
|
+
|
|
13
|
+
import { getWebhook, LIME_CRM_API_CREDENTIAL_KEY } from './commons';
|
|
14
|
+
import { getLimeTypes } from './methods';
|
|
15
|
+
import {
|
|
16
|
+
createSubscription,
|
|
17
|
+
deleteSubscription,
|
|
18
|
+
getSubscription,
|
|
19
|
+
listSubscriptionsWithExistingData,
|
|
20
|
+
} from './transport';
|
|
21
|
+
|
|
22
|
+
export class LimeCrmTrigger implements INodeType {
|
|
23
|
+
description: INodeTypeDescription = {
|
|
24
|
+
displayName: 'Lime CRM Trigger',
|
|
25
|
+
name: 'limeCrmTrigger',
|
|
26
|
+
icon: 'file:assets/lime-crm.svg',
|
|
27
|
+
group: ['trigger'],
|
|
28
|
+
version: 1,
|
|
29
|
+
description:
|
|
30
|
+
'Trigger which handles webhooks coming from Lime, e.g when ' +
|
|
31
|
+
'LimeObject is updated',
|
|
32
|
+
defaults: {
|
|
33
|
+
name: 'Lime CRM Trigger',
|
|
34
|
+
},
|
|
35
|
+
inputs: [],
|
|
36
|
+
outputs: [NodeConnectionType.Main],
|
|
37
|
+
credentials: [
|
|
38
|
+
{
|
|
39
|
+
name: LIME_CRM_API_CREDENTIAL_KEY,
|
|
40
|
+
required: true,
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
webhooks: [
|
|
44
|
+
{
|
|
45
|
+
name: 'default',
|
|
46
|
+
httpMethod: 'POST',
|
|
47
|
+
responseMode: 'onReceived',
|
|
48
|
+
path: 'webhook',
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
properties: [
|
|
52
|
+
{
|
|
53
|
+
displayName: 'Events',
|
|
54
|
+
name: 'events',
|
|
55
|
+
type: 'fixedCollection',
|
|
56
|
+
typeOptions: {
|
|
57
|
+
multipleValues: true,
|
|
58
|
+
required: true,
|
|
59
|
+
},
|
|
60
|
+
default: {},
|
|
61
|
+
placeholder: 'Add Event',
|
|
62
|
+
description: 'Events to subscribe to',
|
|
63
|
+
options: [
|
|
64
|
+
{
|
|
65
|
+
name: 'event',
|
|
66
|
+
displayName: 'Event',
|
|
67
|
+
values: [
|
|
68
|
+
{
|
|
69
|
+
displayName: 'Lime Type',
|
|
70
|
+
name: 'limeType',
|
|
71
|
+
type: 'options',
|
|
72
|
+
typeOptions: {
|
|
73
|
+
loadOptionsMethod: 'getLimeTypes',
|
|
74
|
+
},
|
|
75
|
+
default: '',
|
|
76
|
+
description:
|
|
77
|
+
'Lime Type to subscribe to events for',
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
displayName: 'Event Type',
|
|
81
|
+
name: 'eventType',
|
|
82
|
+
type: 'options',
|
|
83
|
+
options: [
|
|
84
|
+
{
|
|
85
|
+
name: 'New',
|
|
86
|
+
value: 'new',
|
|
87
|
+
description:
|
|
88
|
+
'When a new record is created',
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: 'Update',
|
|
92
|
+
value: 'update',
|
|
93
|
+
description: 'When a record is updated',
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: 'Delete',
|
|
97
|
+
value: 'delete',
|
|
98
|
+
description: 'When a record is deleted',
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
default: 'new',
|
|
102
|
+
description: 'Type of event to subscribe to',
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
displayName: 'Name',
|
|
110
|
+
name: 'name',
|
|
111
|
+
type: 'string',
|
|
112
|
+
default: '',
|
|
113
|
+
placeholder: 'my-lime-webhook',
|
|
114
|
+
required: true,
|
|
115
|
+
description: 'Name for this webhook subscription',
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
methods = {
|
|
121
|
+
loadOptions: {
|
|
122
|
+
getLimeTypes,
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
webhookMethods = {
|
|
127
|
+
default: {
|
|
128
|
+
async checkExists(this: IHookFunctions): Promise<boolean> {
|
|
129
|
+
const webhook = getWebhook(this);
|
|
130
|
+
|
|
131
|
+
if (!webhook.data.webhookId) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const response = await getSubscription(this, webhook);
|
|
136
|
+
if (!response.success) {
|
|
137
|
+
if (response.status === 404) {
|
|
138
|
+
delete webhook.data.webhookId;
|
|
139
|
+
delete webhook.data.webhookEvents;
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
Logger.warn(
|
|
143
|
+
`There was en error while getting a webhook from Lime CRM: ${response.error}`
|
|
144
|
+
);
|
|
145
|
+
throw new NodeOperationError(
|
|
146
|
+
this.getNode(),
|
|
147
|
+
response.error
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
return true;
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
async create(this: IHookFunctions): Promise<boolean> {
|
|
154
|
+
const webhook = getWebhook(this);
|
|
155
|
+
const webhookUrl = webhook.url;
|
|
156
|
+
if (!webhookUrl) {
|
|
157
|
+
throw new NodeOperationError(
|
|
158
|
+
this.getNode(),
|
|
159
|
+
'Invalid Webhook URL. Please make sure that it is not localhost!'
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Check if a webhook already exists in order to not duplicate it in Lime
|
|
164
|
+
// This is a different check then 'checkExists' which only takes an ID,
|
|
165
|
+
// but it's only suited for production environment
|
|
166
|
+
|
|
167
|
+
const existingSubscriptionResponse =
|
|
168
|
+
await listSubscriptionsWithExistingData(this, webhook);
|
|
169
|
+
if (!existingSubscriptionResponse.success) {
|
|
170
|
+
throw new NodeOperationError(
|
|
171
|
+
this.getNode(),
|
|
172
|
+
existingSubscriptionResponse.error
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (existingSubscriptionResponse.data.length === 0) {
|
|
177
|
+
const createSubscriptionResponse = await createSubscription(
|
|
178
|
+
this,
|
|
179
|
+
webhook
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
if (!createSubscriptionResponse.success) {
|
|
183
|
+
throw new NodeOperationError(
|
|
184
|
+
this.getNode(),
|
|
185
|
+
createSubscriptionResponse.error
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const subscriptionId = createSubscriptionResponse.data.id;
|
|
190
|
+
const events = createSubscriptionResponse.data.events;
|
|
191
|
+
|
|
192
|
+
webhook.data.webhookId = subscriptionId;
|
|
193
|
+
webhook.data.webhookEvents = events;
|
|
194
|
+
Logger.info(
|
|
195
|
+
`Webhook with URL ${webhook.url}, ID ${subscriptionId} and events ${events} created!`
|
|
196
|
+
);
|
|
197
|
+
return true;
|
|
198
|
+
} else {
|
|
199
|
+
const limeWebhook = existingSubscriptionResponse.data[0];
|
|
200
|
+
webhook.data.webhookId = limeWebhook.id;
|
|
201
|
+
webhook.data.webhookEvents = limeWebhook.events;
|
|
202
|
+
Logger.info(
|
|
203
|
+
`Webhook with URL ${webhook.url}, and events ${webhook.events} exists in Lime.
|
|
204
|
+
ID ${limeWebhook.id} set up to the N8N data.`
|
|
205
|
+
);
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
|
|
210
|
+
async delete(this: IHookFunctions): Promise<boolean> {
|
|
211
|
+
const webhook = getWebhook(this);
|
|
212
|
+
Logger.info(
|
|
213
|
+
`Deleting webhook with ID: ${webhook.data.webhookId}`,
|
|
214
|
+
{ ...webhook }
|
|
215
|
+
);
|
|
216
|
+
if (webhook.data.webhookId !== undefined) {
|
|
217
|
+
const response = await deleteSubscription(this, webhook);
|
|
218
|
+
if (!response.success) {
|
|
219
|
+
Logger.error(
|
|
220
|
+
`Failed to delete webhook with ID: ${webhook.data.webhookId}`,
|
|
221
|
+
{
|
|
222
|
+
...webhook,
|
|
223
|
+
}
|
|
224
|
+
);
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
delete webhook.data.webhookId;
|
|
228
|
+
Logger.info('Webhook deleted successfully', { ...webhook });
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
return false;
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
|
|
237
|
+
const webhook = getWebhook(this);
|
|
238
|
+
Logger.info('Webhook received. Starting webhook processing...', {
|
|
239
|
+
...webhook.context,
|
|
240
|
+
});
|
|
241
|
+
const bodyData = this.getBodyData();
|
|
242
|
+
|
|
243
|
+
if (!bodyData || !bodyData.event || !bodyData.body) {
|
|
244
|
+
Logger.warn('Webhook data is invalid. Missing event or body', {
|
|
245
|
+
...webhook.context,
|
|
246
|
+
});
|
|
247
|
+
throw new NodeOperationError(
|
|
248
|
+
this.getNode(),
|
|
249
|
+
'Webhook data is invalid'
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const returnData: IDataObject[] = [];
|
|
254
|
+
|
|
255
|
+
returnData.push({
|
|
256
|
+
body: bodyData,
|
|
257
|
+
headers: this.getHeaderData(),
|
|
258
|
+
query: this.getQueryData(),
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
return { workflowData: [this.helpers.returnJsonArray(returnData)] };
|
|
262
|
+
}
|
|
263
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 1024 1025" xmlns="http://www.w3.org/2000/svg" xml:space="preserve"><clipPath id="a"><path d="M0 .03h1024v1024H0z"/></clipPath><g clip-path="url(#a)"><path d="M92.399 480.888c0-257.059 208.719-465.779 465.78-465.779C815.28 15.109 1024 223.829 1024 480.888c0 133.713-55.806 271.139-193.403 385.355-166.779 138.45-390.39 157.35-736.15 134.525-102.653-6.785-117.502-24.319-64.468-63.444 166.694-123.047 62.42-217.167 62.42-456.436Z" style="fill:#bee034"/><clipPath id="b"><path d="M92.399 480.888c0-257.059 208.719-465.779 465.78-465.779C815.28 15.109 1024 223.829 1024 480.888c0 133.713-55.806 271.139-193.403 385.355-166.779 138.45-390.39 157.35-736.15 134.525-102.653-6.785-117.502-24.319-64.468-63.444 166.694-123.047 62.42-217.167 62.42-456.436Z"/></clipPath><g clip-path="url(#b)"><path d="M1023-361.59c0 784.587-711.326 1420.62-1588.79 1420.62C-1402.638-283.55 1023-1146.18 1023-361.59Z" style="fill:#a6efff;filter:blur(200px)"/></g><path d="M433.85 723.911c-24.702-12.757-47.23-29.226-66.813-48.596-9.088-9.002-23.765-8.959-32.768.129-9.001 9.087-8.916 23.763.171 32.766 22.911 22.698 49.236 41.941 78.121 56.873 11.392 5.888 25.385 1.409 31.231-9.94 5.888-11.349 1.409-25.344-9.942-31.232Zm367.266-363.98a270.163 270.163 0 0 1 25.556 78.547c2.048 12.629 13.952 21.206 26.581 19.158 12.586-2.006 21.204-13.951 19.156-26.539a316.387 316.387 0 0 0-29.907-92.029c-5.803-11.434-19.754-15.999-31.146-10.24-11.393 5.76-16 19.713-10.24 31.103Zm-51.497 315.384c-19.584 19.37-42.069 35.839-66.815 48.596-11.349 5.888-15.786 19.883-9.94 31.232 5.887 11.349 19.881 15.828 31.229 9.94 28.929-14.932 55.253-34.175 78.164-56.873 9.045-9.003 9.131-23.679.128-32.766-9.002-9.088-23.678-9.131-32.766-.129ZM517.006 213.546a274.904 274.904 0 0 1 41.343-3.114c14.036 0 27.861 1.066 41.343 3.114 12.629 1.919 24.448-6.784 26.367-19.413 1.962-12.628-6.741-24.446-19.371-26.409a322.626 322.626 0 0 0-48.339-3.627 322.201 322.201 0 0 0-48.34 3.627c-12.672 1.963-21.332 13.781-19.413 26.409 1.92 12.629 13.739 21.332 26.41 19.413Zm41.343 490.355c-40.489 0-73.385 32.853-73.385 73.342s32.896 73.385 73.385 73.385c40.489 0 73.342-32.896 73.342-73.385 0-40.489-32.853-73.342-73.342-73.342ZM290.025 438.478c4.481-27.818 13.227-54.227 25.514-78.547 5.761-11.39 1.195-25.343-10.239-31.103-11.392-5.759-25.343-1.194-31.104 10.24a313.893 313.893 0 0 0-29.908 92.029c-2.048 12.588 6.527 24.533 19.157 26.539 12.629 2.048 24.532-6.529 26.58-19.158Zm479.092 112.254c-12.501 38.527 8.618 79.955 47.102 92.456 38.528 12.502 79.956-8.618 92.457-47.104 12.501-38.525-8.619-79.953-47.103-92.455-38.527-12.501-79.955 8.619-92.456 47.103Zm-80.51-247.802c32.766 23.808 78.675 16.554 102.482-16.212 23.808-32.767 16.512-78.675-16.256-102.482-32.723-23.809-78.675-16.512-102.439 16.254-23.808 32.725-16.555 78.633 16.213 102.44Zm-260.558 0c32.766-23.807 40.063-69.715 16.254-102.44-23.807-32.766-69.715-40.063-102.482-16.254-32.766 23.807-40.02 69.715-16.255 102.482 23.806 32.766 69.758 40.02 102.483 16.212Zm-80.51 247.802c-12.501-38.484-53.929-59.604-92.415-47.103-38.526 12.502-59.645 53.93-47.102 92.455 12.501 38.486 53.929 59.606 92.413 47.104 38.528-12.501 59.605-53.929 47.104-92.456Z" style="fill:#fff"/></g></svg>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { getTasks } from '../transport/task';
|
|
2
|
+
import { IExecuteFunctions } from 'n8n-workflow';
|
|
3
|
+
|
|
4
|
+
export async function waitForTaskCompletion(
|
|
5
|
+
nodeContext: IExecuteFunctions,
|
|
6
|
+
taskId: string,
|
|
7
|
+
pollInterval: number,
|
|
8
|
+
timeout: number
|
|
9
|
+
) {
|
|
10
|
+
const startTime = Date.now();
|
|
11
|
+
|
|
12
|
+
while (Date.now() - startTime <= timeout) {
|
|
13
|
+
const taskResponse = await getTasks(nodeContext, taskId);
|
|
14
|
+
|
|
15
|
+
if (!taskResponse.success) continue;
|
|
16
|
+
|
|
17
|
+
const task = taskResponse.data._embedded.tasks[0];
|
|
18
|
+
switch (task.status) {
|
|
19
|
+
case 'FAILURE': {
|
|
20
|
+
return {
|
|
21
|
+
success: false,
|
|
22
|
+
error: `Task ${taskId} failed: ${task.result}`,
|
|
23
|
+
metadata: {
|
|
24
|
+
taskId: taskId,
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
case 'REVOKED': {
|
|
29
|
+
return {
|
|
30
|
+
success: false,
|
|
31
|
+
error: `Task ${taskId} was revoked`,
|
|
32
|
+
metadata: {
|
|
33
|
+
taskId: taskId,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
case 'SUCCESS': {
|
|
38
|
+
return {
|
|
39
|
+
success: true,
|
|
40
|
+
data: task.result,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
success: false,
|
|
50
|
+
error: `Task ${taskId} did not complete within ${timeout / 1000}s`,
|
|
51
|
+
metadata: {
|
|
52
|
+
taskId: taskId,
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { IDataObject, IHookFunctions, IWebhookFunctions } from 'n8n-workflow';
|
|
2
|
+
|
|
3
|
+
type WebhookFunctions = IHookFunctions | IWebhookFunctions;
|
|
4
|
+
|
|
5
|
+
interface WebhookContext {
|
|
6
|
+
nodeId: string;
|
|
7
|
+
nodeName?: string;
|
|
8
|
+
workflowId?: string;
|
|
9
|
+
workflowName?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface Webhook {
|
|
13
|
+
data: IDataObject;
|
|
14
|
+
events: string[];
|
|
15
|
+
url?: string;
|
|
16
|
+
context: WebhookContext;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function _getEvents(hookData: WebhookFunctions): string[] {
|
|
20
|
+
const eventData = hookData.getNodeParameter('events', []) as {
|
|
21
|
+
event: Array<{
|
|
22
|
+
limeType: string;
|
|
23
|
+
eventType: string;
|
|
24
|
+
}>;
|
|
25
|
+
};
|
|
26
|
+
const eventItems = eventData.event;
|
|
27
|
+
const events: string[] = [];
|
|
28
|
+
for (const eventItem of eventItems) {
|
|
29
|
+
events.push(`${eventItem.limeType}.${eventItem.eventType}`);
|
|
30
|
+
}
|
|
31
|
+
return events;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function getWebhook(hookData: WebhookFunctions): Webhook {
|
|
35
|
+
const node = hookData.getNode();
|
|
36
|
+
const workflow = hookData.getWorkflow();
|
|
37
|
+
const context: WebhookContext = {
|
|
38
|
+
nodeId: node.id,
|
|
39
|
+
nodeName: node.name,
|
|
40
|
+
workflowId: workflow.id,
|
|
41
|
+
workflowName: workflow.name,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
data: hookData.getWorkflowStaticData('node'),
|
|
46
|
+
events: _getEvents(hookData),
|
|
47
|
+
url: hookData.getNodeWebhookUrl('default'),
|
|
48
|
+
context: context,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ILoadOptionsFunctions } from 'n8n-workflow';
|
|
2
|
+
|
|
3
|
+
export async function getEntitiesForErpSystem(this: ILoadOptionsFunctions) {
|
|
4
|
+
const erpSystem = this.getCurrentNodeParameter('erpSystem') as string;
|
|
5
|
+
|
|
6
|
+
if (erpSystem === 'fortnox') {
|
|
7
|
+
return [{ name: 'Invoice', value: 'invoice' }];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return [];
|
|
11
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ILoadOptionsFunctions,
|
|
3
|
+
INodePropertyOptions,
|
|
4
|
+
LoggerProxy as Logger,
|
|
5
|
+
} from 'n8n-workflow';
|
|
6
|
+
import { getProperties } from '../transport/';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Load properties for a selected Lime type
|
|
10
|
+
*/
|
|
11
|
+
export async function getLimeTypeProperties(
|
|
12
|
+
this: ILoadOptionsFunctions
|
|
13
|
+
): Promise<INodePropertyOptions[]> {
|
|
14
|
+
const limeType = this.getNodeParameter('limeType', '') as string;
|
|
15
|
+
Logger.info(`Fetching properties for Lime type: ${limeType}`);
|
|
16
|
+
if (!limeType) return [];
|
|
17
|
+
|
|
18
|
+
const response = await getProperties(this, limeType);
|
|
19
|
+
|
|
20
|
+
if (!response.success) return [];
|
|
21
|
+
|
|
22
|
+
return response.data.map((property) => ({
|
|
23
|
+
name: (property.localname as string) || (property.name as string),
|
|
24
|
+
value: property.name as string,
|
|
25
|
+
description: `Type: ${property.type as string}${(property.required as boolean) ? ' (Required)' : ''}`,
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ILoadOptionsFunctions, INodePropertyOptions } from 'n8n-workflow';
|
|
2
|
+
import { getLimeTypesFromApi } from '../transport';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Load available Lime types from the API
|
|
6
|
+
*/
|
|
7
|
+
export async function getLimeTypes(
|
|
8
|
+
this: ILoadOptionsFunctions
|
|
9
|
+
): Promise<INodePropertyOptions[]> {
|
|
10
|
+
const data: INodePropertyOptions[] = [];
|
|
11
|
+
const response = await getLimeTypesFromApi(this);
|
|
12
|
+
if (response.success && response.data) {
|
|
13
|
+
for (const limeType of response.data) {
|
|
14
|
+
if (limeType.name) {
|
|
15
|
+
data.push({
|
|
16
|
+
name: limeType.name,
|
|
17
|
+
value: limeType.name,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return data;
|
|
23
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IExecuteFunctions,
|
|
3
|
+
INodeProperties,
|
|
4
|
+
NodePropertyTypes,
|
|
5
|
+
} from 'n8n-workflow';
|
|
6
|
+
|
|
7
|
+
import * as createOrUpdateObjects from './operations/createOrUpdateObjects.operation';
|
|
8
|
+
import * as transform from './operations/transform.operation';
|
|
9
|
+
|
|
10
|
+
import { ERP_CONNECTOR_RESOURCE } from '../../commons';
|
|
11
|
+
|
|
12
|
+
export const erpConnectorFields: INodeProperties[] = [
|
|
13
|
+
{
|
|
14
|
+
displayName: 'Operation',
|
|
15
|
+
name: 'operation',
|
|
16
|
+
type: 'options' as NodePropertyTypes,
|
|
17
|
+
noDataExpression: true,
|
|
18
|
+
displayOptions: {
|
|
19
|
+
show: {
|
|
20
|
+
resource: [ERP_CONNECTOR_RESOURCE],
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
options: [createOrUpdateObjects.description, transform.description],
|
|
24
|
+
default: 'transformErpData',
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
...createOrUpdateObjects.properties,
|
|
28
|
+
...transform.properties,
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
export async function erpConnectorOperations(
|
|
32
|
+
this: IExecuteFunctions,
|
|
33
|
+
{ operation, i }: { operation: string; i: number }
|
|
34
|
+
) {
|
|
35
|
+
if (operation === 'createOrUpdateObjects') {
|
|
36
|
+
return await createOrUpdateObjects.execute.call(this, i);
|
|
37
|
+
}
|
|
38
|
+
if (operation === 'transformErpData') {
|
|
39
|
+
return await transform.execute.call(this, i);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return null;
|
|
43
|
+
}
|