n8n-nodes-synca 1.0.27 → 1.0.29

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.
@@ -0,0 +1,721 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SyncaMarketplace = void 0;
4
+ function buildProductParams(index, operation, getNodeParameter) {
5
+ const params = {};
6
+ switch (operation) {
7
+ case 'upsert_product': {
8
+ params.sku = getNodeParameter('sku', index);
9
+ params.name = getNodeParameter('name', index);
10
+ params.base_price = getNodeParameter('base_price', index);
11
+ const additionalFields = getNodeParameter('additionalFields', index, {});
12
+ if (additionalFields.images) {
13
+ additionalFields.images = additionalFields.images.split(',').map((s) => s.trim());
14
+ }
15
+ if (additionalFields.attributes && typeof additionalFields.attributes === 'string') {
16
+ additionalFields.attributes = JSON.parse(additionalFields.attributes);
17
+ }
18
+ if (additionalFields.localized_names && typeof additionalFields.localized_names === 'string') {
19
+ additionalFields.localized_names = JSON.parse(additionalFields.localized_names);
20
+ }
21
+ Object.assign(params, additionalFields);
22
+ break;
23
+ }
24
+ case 'get_product':
25
+ case 'delete_product':
26
+ params.product_id = getNodeParameter('product_id', index);
27
+ break;
28
+ case 'list_products_for_destination':
29
+ params.destination_id = getNodeParameter('destination_id', index);
30
+ break;
31
+ case 'record_sync_result':
32
+ params.product_id = getNodeParameter('product_id', index);
33
+ params.destination_id = getNodeParameter('destination_id', index);
34
+ params.external_id = getNodeParameter('external_id', index);
35
+ params.status = getNodeParameter('sync_status', index);
36
+ try {
37
+ params.error = getNodeParameter('sync_error', index, '');
38
+ }
39
+ catch {
40
+ }
41
+ break;
42
+ }
43
+ return params;
44
+ }
45
+ function buildOrderParams(index, operation, getNodeParameter) {
46
+ const params = {};
47
+ switch (operation) {
48
+ case 'create_order': {
49
+ params.source_destination_id = getNodeParameter('source_destination_id', index);
50
+ params.source_order_id = getNodeParameter('source_order_id', index);
51
+ params.total = getNodeParameter('total', index);
52
+ const customerData = getNodeParameter('customer.customerData', index, {});
53
+ params.customer = {
54
+ name: customerData.name,
55
+ email: customerData.email,
56
+ phone: customerData.phone,
57
+ address: {
58
+ street: customerData.street,
59
+ city: customerData.city,
60
+ postal_code: customerData.postal_code,
61
+ country: customerData.country,
62
+ },
63
+ };
64
+ const itemsJson = getNodeParameter('items', index);
65
+ params.items = typeof itemsJson === 'string' ? JSON.parse(itemsJson) : itemsJson;
66
+ const additionalFields = getNodeParameter('orderAdditionalFields', index, {});
67
+ if (additionalFields.source_raw_data && typeof additionalFields.source_raw_data === 'string') {
68
+ additionalFields.source_raw_data = JSON.parse(additionalFields.source_raw_data);
69
+ }
70
+ Object.assign(params, additionalFields);
71
+ break;
72
+ }
73
+ case 'get_order':
74
+ params.order_id = getNodeParameter('order_id', index);
75
+ break;
76
+ case 'update_order_status': {
77
+ params.order_id = getNodeParameter('order_id', index);
78
+ params.status = getNodeParameter('status', index);
79
+ const erpInfo = getNodeParameter('erpSyncInfo', index, {});
80
+ if (Object.keys(erpInfo).length > 0) {
81
+ params.erp_data = erpInfo;
82
+ }
83
+ break;
84
+ }
85
+ }
86
+ return params;
87
+ }
88
+ class SyncaMarketplace {
89
+ constructor() {
90
+ this.description = {
91
+ displayName: 'Synca Marketplace',
92
+ name: 'syncaMarketplace',
93
+ icon: { light: 'file:marketplace.svg', dark: 'file:marketplace.svg' },
94
+ group: ['transform'],
95
+ version: 1,
96
+ description: 'Manage unified product catalog and orders across all your sales channels',
97
+ subtitle: '={{$parameter["resource"] + ": " + $parameter["operation"]}}',
98
+ defaults: { name: 'Synca Marketplace' },
99
+ inputs: ["main"],
100
+ outputs: ["main"],
101
+ usableAsTool: true,
102
+ credentials: [{ name: 'syncaApiCredentials', required: true }],
103
+ properties: [
104
+ {
105
+ displayName: 'Resource',
106
+ name: 'resource',
107
+ type: 'options',
108
+ noDataExpression: true,
109
+ options: [
110
+ {
111
+ name: 'Product',
112
+ value: 'product',
113
+ description: 'Manage products in your unified catalog',
114
+ },
115
+ {
116
+ name: 'Order',
117
+ value: 'order',
118
+ description: 'Manage orders from all sales channels',
119
+ },
120
+ {
121
+ name: 'Destination',
122
+ value: 'destination',
123
+ description: 'Manage marketplace destinations (sales channels)',
124
+ },
125
+ ],
126
+ default: 'product',
127
+ },
128
+ {
129
+ displayName: 'Operation',
130
+ name: 'operation',
131
+ type: 'options',
132
+ noDataExpression: true,
133
+ displayOptions: { show: { resource: ['product'] } },
134
+ options: [
135
+ {
136
+ name: 'Add or Update',
137
+ value: 'upsert_product',
138
+ description: 'Add a new product or update existing by SKU',
139
+ action: 'Add or update product',
140
+ },
141
+ {
142
+ name: 'Get Many',
143
+ value: 'list_products',
144
+ description: 'Get all products from the catalog',
145
+ action: 'Get many products',
146
+ },
147
+ {
148
+ name: 'Get Many for Destination',
149
+ value: 'list_products_for_destination',
150
+ description: 'Get products formatted for a specific destination with calculated prices',
151
+ action: 'Get products for destination',
152
+ },
153
+ {
154
+ name: 'Get',
155
+ value: 'get_product',
156
+ description: 'Get a single product by ID',
157
+ action: 'Get product',
158
+ },
159
+ {
160
+ name: 'Delete',
161
+ value: 'delete_product',
162
+ description: 'Delete a product from the catalog',
163
+ action: 'Delete product',
164
+ },
165
+ {
166
+ name: 'Record Sync Result',
167
+ value: 'record_sync_result',
168
+ description: 'Record the result after syncing to a provider',
169
+ action: 'Record sync result',
170
+ },
171
+ ],
172
+ default: 'upsert_product',
173
+ },
174
+ {
175
+ displayName: 'Operation',
176
+ name: 'operation',
177
+ type: 'options',
178
+ noDataExpression: true,
179
+ displayOptions: { show: { resource: ['order'] } },
180
+ options: [
181
+ {
182
+ name: 'Create',
183
+ value: 'create_order',
184
+ description: 'Create a new order from a sales channel',
185
+ action: 'Create order',
186
+ },
187
+ {
188
+ name: 'Get Many',
189
+ value: 'list_orders',
190
+ description: 'Get all orders',
191
+ action: 'Get many orders',
192
+ },
193
+ {
194
+ name: 'Get',
195
+ value: 'get_order',
196
+ description: 'Get a single order by ID',
197
+ action: 'Get order',
198
+ },
199
+ {
200
+ name: 'Update Status',
201
+ value: 'update_order_status',
202
+ description: 'Update order status and ERP sync info',
203
+ action: 'Update order status',
204
+ },
205
+ ],
206
+ default: 'create_order',
207
+ },
208
+ {
209
+ displayName: 'Operation',
210
+ name: 'operation',
211
+ type: 'options',
212
+ noDataExpression: true,
213
+ displayOptions: { show: { resource: ['destination'] } },
214
+ options: [
215
+ {
216
+ name: 'Get Many',
217
+ value: 'list_destinations',
218
+ description: 'Get all configured destinations',
219
+ action: 'Get many destinations',
220
+ },
221
+ {
222
+ name: 'Get',
223
+ value: 'get_destination',
224
+ description: 'Get a single destination',
225
+ action: 'Get destination',
226
+ },
227
+ ],
228
+ default: 'list_destinations',
229
+ },
230
+ {
231
+ displayName: 'Destination',
232
+ name: 'destination_id',
233
+ type: 'options',
234
+ typeOptions: { loadOptionsMethod: 'getDestinations' },
235
+ required: true,
236
+ displayOptions: {
237
+ show: {
238
+ resource: ['product'],
239
+ operation: ['list_products_for_destination', 'record_sync_result'],
240
+ },
241
+ },
242
+ default: '',
243
+ description: 'The destination to get products for',
244
+ },
245
+ {
246
+ displayName: 'Product ID',
247
+ name: 'product_id',
248
+ type: 'string',
249
+ required: true,
250
+ displayOptions: {
251
+ show: {
252
+ resource: ['product'],
253
+ operation: ['get_product', 'delete_product', 'record_sync_result'],
254
+ },
255
+ },
256
+ default: '',
257
+ description: 'The marketplace product ID',
258
+ },
259
+ {
260
+ displayName: 'SKU',
261
+ name: 'sku',
262
+ type: 'string',
263
+ required: true,
264
+ displayOptions: {
265
+ show: {
266
+ resource: ['product'],
267
+ operation: ['upsert_product'],
268
+ },
269
+ },
270
+ default: '',
271
+ description: 'Unique product identifier (Stock Keeping Unit)',
272
+ },
273
+ {
274
+ displayName: 'Name',
275
+ name: 'name',
276
+ type: 'string',
277
+ required: true,
278
+ displayOptions: {
279
+ show: {
280
+ resource: ['product'],
281
+ operation: ['upsert_product'],
282
+ },
283
+ },
284
+ default: '',
285
+ description: 'Product name',
286
+ },
287
+ {
288
+ displayName: 'Base Price',
289
+ name: 'base_price',
290
+ type: 'number',
291
+ required: true,
292
+ displayOptions: {
293
+ show: {
294
+ resource: ['product'],
295
+ operation: ['upsert_product'],
296
+ },
297
+ },
298
+ default: 0,
299
+ description: 'Base price before any destination-specific adjustments',
300
+ },
301
+ {
302
+ displayName: 'Additional Fields',
303
+ name: 'additionalFields',
304
+ type: 'collection',
305
+ placeholder: 'Add Field',
306
+ default: {},
307
+ displayOptions: {
308
+ show: {
309
+ resource: ['product'],
310
+ operation: ['upsert_product'],
311
+ },
312
+ },
313
+ options: [
314
+ {
315
+ displayName: 'Description',
316
+ name: 'description',
317
+ type: 'string',
318
+ typeOptions: { rows: 4 },
319
+ default: '',
320
+ },
321
+ {
322
+ displayName: 'Currency',
323
+ name: 'currency',
324
+ type: 'string',
325
+ default: 'ILS',
326
+ },
327
+ {
328
+ displayName: 'Images',
329
+ name: 'images',
330
+ type: 'string',
331
+ default: '',
332
+ description: 'Comma-separated list of image URLs',
333
+ },
334
+ {
335
+ displayName: 'In Stock',
336
+ name: 'in_stock',
337
+ type: 'boolean',
338
+ default: true,
339
+ },
340
+ {
341
+ displayName: 'Quantity',
342
+ name: 'quantity',
343
+ type: 'number',
344
+ default: null,
345
+ },
346
+ {
347
+ displayName: 'Source Provider',
348
+ name: 'source_provider',
349
+ type: 'string',
350
+ default: '',
351
+ description: 'Name of the source system (e.g., priority, sap)',
352
+ },
353
+ {
354
+ displayName: 'Source External ID',
355
+ name: 'source_external_id',
356
+ type: 'string',
357
+ default: '',
358
+ description: 'ID of the product in the source system',
359
+ },
360
+ {
361
+ displayName: 'Attributes (JSON)',
362
+ name: 'attributes',
363
+ type: 'json',
364
+ default: '{}',
365
+ description: 'Additional attributes as JSON',
366
+ },
367
+ {
368
+ displayName: 'Localized Names (JSON)',
369
+ name: 'localized_names',
370
+ type: 'json',
371
+ default: '{}',
372
+ description: 'Names in different languages: {"he": "שם", "en": "Name"}',
373
+ },
374
+ ],
375
+ },
376
+ {
377
+ displayName: 'External ID',
378
+ name: 'external_id',
379
+ type: 'string',
380
+ required: true,
381
+ displayOptions: {
382
+ show: {
383
+ resource: ['product'],
384
+ operation: ['record_sync_result'],
385
+ },
386
+ },
387
+ default: '',
388
+ description: 'The ID assigned by the external provider',
389
+ },
390
+ {
391
+ displayName: 'Sync Status',
392
+ name: 'sync_status',
393
+ type: 'options',
394
+ required: true,
395
+ displayOptions: {
396
+ show: {
397
+ resource: ['product'],
398
+ operation: ['record_sync_result'],
399
+ },
400
+ },
401
+ options: [
402
+ { name: 'Synced', value: 'synced' },
403
+ { name: 'Error', value: 'error' },
404
+ ],
405
+ default: 'synced',
406
+ },
407
+ {
408
+ displayName: 'Error Message',
409
+ name: 'sync_error',
410
+ type: 'string',
411
+ displayOptions: {
412
+ show: {
413
+ resource: ['product'],
414
+ operation: ['record_sync_result'],
415
+ sync_status: ['error'],
416
+ },
417
+ },
418
+ default: '',
419
+ },
420
+ {
421
+ displayName: 'Source Destination',
422
+ name: 'source_destination_id',
423
+ type: 'options',
424
+ typeOptions: { loadOptionsMethod: 'getDestinations' },
425
+ required: true,
426
+ displayOptions: {
427
+ show: {
428
+ resource: ['order'],
429
+ operation: ['create_order'],
430
+ },
431
+ },
432
+ default: '',
433
+ description: 'The sales channel this order came from',
434
+ },
435
+ {
436
+ displayName: 'Source Order ID',
437
+ name: 'source_order_id',
438
+ type: 'string',
439
+ required: true,
440
+ displayOptions: {
441
+ show: {
442
+ resource: ['order'],
443
+ operation: ['create_order'],
444
+ },
445
+ },
446
+ default: '',
447
+ description: 'Original order ID from the sales channel',
448
+ },
449
+ {
450
+ displayName: 'Order ID',
451
+ name: 'order_id',
452
+ type: 'string',
453
+ required: true,
454
+ displayOptions: {
455
+ show: {
456
+ resource: ['order'],
457
+ operation: ['get_order', 'update_order_status'],
458
+ },
459
+ },
460
+ default: '',
461
+ },
462
+ {
463
+ displayName: 'Customer',
464
+ name: 'customer',
465
+ type: 'fixedCollection',
466
+ required: true,
467
+ displayOptions: {
468
+ show: {
469
+ resource: ['order'],
470
+ operation: ['create_order'],
471
+ },
472
+ },
473
+ default: {},
474
+ options: [
475
+ {
476
+ name: 'customerData',
477
+ displayName: 'Customer Data',
478
+ values: [
479
+ { displayName: 'Name', name: 'name', type: 'string', default: '', required: true },
480
+ { displayName: 'Email', name: 'email', type: 'string', default: '' },
481
+ { displayName: 'Phone', name: 'phone', type: 'string', default: '' },
482
+ { displayName: 'Street', name: 'street', type: 'string', default: '' },
483
+ { displayName: 'City', name: 'city', type: 'string', default: '' },
484
+ { displayName: 'Postal Code', name: 'postal_code', type: 'string', default: '' },
485
+ { displayName: 'Country', name: 'country', type: 'string', default: 'IL' },
486
+ ],
487
+ },
488
+ ],
489
+ },
490
+ {
491
+ displayName: 'Items (JSON)',
492
+ name: 'items',
493
+ type: 'json',
494
+ required: true,
495
+ displayOptions: {
496
+ show: {
497
+ resource: ['order'],
498
+ operation: ['create_order'],
499
+ },
500
+ },
501
+ default: '[]',
502
+ description: 'Array of order items: [{"sku": "ABC", "name": "Product", "quantity": 1, "unit_price": 10, "total_price": 10}]',
503
+ },
504
+ {
505
+ displayName: 'Total',
506
+ name: 'total',
507
+ type: 'number',
508
+ required: true,
509
+ displayOptions: {
510
+ show: {
511
+ resource: ['order'],
512
+ operation: ['create_order'],
513
+ },
514
+ },
515
+ default: 0,
516
+ },
517
+ {
518
+ displayName: 'Additional Fields',
519
+ name: 'orderAdditionalFields',
520
+ type: 'collection',
521
+ placeholder: 'Add Field',
522
+ default: {},
523
+ displayOptions: {
524
+ show: {
525
+ resource: ['order'],
526
+ operation: ['create_order'],
527
+ },
528
+ },
529
+ options: [
530
+ { displayName: 'Subtotal', name: 'subtotal', type: 'number', default: 0 },
531
+ { displayName: 'Discount', name: 'discount', type: 'number', default: 0 },
532
+ { displayName: 'Delivery Fee', name: 'delivery_fee', type: 'number', default: 0 },
533
+ { displayName: 'Currency', name: 'currency', type: 'string', default: 'ILS' },
534
+ {
535
+ displayName: 'Ordered At',
536
+ name: 'ordered_at',
537
+ type: 'dateTime',
538
+ default: '',
539
+ description: 'When the order was placed (defaults to now)',
540
+ },
541
+ {
542
+ displayName: 'Source Raw Data (JSON)',
543
+ name: 'source_raw_data',
544
+ type: 'json',
545
+ default: '{}',
546
+ description: 'Original order data from the source',
547
+ },
548
+ ],
549
+ },
550
+ {
551
+ displayName: 'Status',
552
+ name: 'status',
553
+ type: 'options',
554
+ required: true,
555
+ displayOptions: {
556
+ show: {
557
+ resource: ['order'],
558
+ operation: ['update_order_status'],
559
+ },
560
+ },
561
+ options: [
562
+ { name: 'New', value: 'new' },
563
+ { name: 'Processing', value: 'processing' },
564
+ { name: 'Ready', value: 'ready' },
565
+ { name: 'Shipped', value: 'shipped' },
566
+ { name: 'Delivered', value: 'delivered' },
567
+ { name: 'Cancelled', value: 'cancelled' },
568
+ ],
569
+ default: 'processing',
570
+ },
571
+ {
572
+ displayName: 'ERP Sync Info',
573
+ name: 'erpSyncInfo',
574
+ type: 'collection',
575
+ placeholder: 'Add ERP Info',
576
+ default: {},
577
+ displayOptions: {
578
+ show: {
579
+ resource: ['order'],
580
+ operation: ['update_order_status'],
581
+ },
582
+ },
583
+ options: [
584
+ {
585
+ displayName: 'ERP Sync Status',
586
+ name: 'erp_sync_status',
587
+ type: 'options',
588
+ options: [
589
+ { name: 'Pending', value: 'pending' },
590
+ { name: 'Synced', value: 'synced' },
591
+ { name: 'Error', value: 'error' },
592
+ { name: 'Skipped', value: 'skipped' },
593
+ ],
594
+ default: 'synced',
595
+ },
596
+ { displayName: 'ERP Order ID', name: 'erp_order_id', type: 'string', default: '' },
597
+ { displayName: 'ERP Credential ID', name: 'erp_credential_id', type: 'string', default: '' },
598
+ { displayName: 'ERP Sync Error', name: 'erp_sync_error', type: 'string', default: '' },
599
+ ],
600
+ },
601
+ {
602
+ displayName: 'Filters',
603
+ name: 'filters',
604
+ type: 'collection',
605
+ placeholder: 'Add Filter',
606
+ default: {},
607
+ displayOptions: {
608
+ show: {
609
+ resource: ['product', 'order'],
610
+ operation: ['list_products', 'list_products_for_destination', 'list_orders'],
611
+ },
612
+ },
613
+ options: [
614
+ {
615
+ displayName: 'Status',
616
+ name: 'status',
617
+ type: 'string',
618
+ default: '',
619
+ },
620
+ {
621
+ displayName: 'Limit',
622
+ name: 'limit',
623
+ type: 'number',
624
+ default: 50,
625
+ },
626
+ {
627
+ displayName: 'Offset',
628
+ name: 'offset',
629
+ type: 'number',
630
+ default: 0,
631
+ },
632
+ ],
633
+ },
634
+ ],
635
+ };
636
+ this.methods = {
637
+ loadOptions: {
638
+ async getDestinations() {
639
+ try {
640
+ const { apiToken, baseUrl } = await this.getCredentials('syncaApiCredentials');
641
+ const response = await this.helpers.httpRequest({
642
+ method: 'POST',
643
+ url: `${baseUrl}/v1/marketplace/list_destinations`,
644
+ headers: { 'x-api-token': apiToken },
645
+ json: true,
646
+ });
647
+ if (response.success && Array.isArray(response.data)) {
648
+ return response.data.map((d) => ({
649
+ name: `${d.name} (${d.provider_type})`,
650
+ value: d.id,
651
+ }));
652
+ }
653
+ return [];
654
+ }
655
+ catch {
656
+ return [];
657
+ }
658
+ },
659
+ },
660
+ };
661
+ }
662
+ async execute() {
663
+ var _a;
664
+ const items = this.getInputData();
665
+ const results = [];
666
+ const { apiToken, baseUrl } = await this.getCredentials('syncaApiCredentials');
667
+ for (let i = 0; i < items.length; i++) {
668
+ try {
669
+ const resource = this.getNodeParameter('resource', i);
670
+ const operation = this.getNodeParameter('operation', i);
671
+ let params = {};
672
+ if (resource === 'product') {
673
+ params = buildProductParams(i, operation, this.getNodeParameter);
674
+ }
675
+ else if (resource === 'order') {
676
+ params = buildOrderParams(i, operation, this.getNodeParameter);
677
+ }
678
+ if (['list_products', 'list_products_for_destination', 'list_orders'].includes(operation)) {
679
+ const filters = this.getNodeParameter('filters', i, {});
680
+ params = { ...params, ...filters };
681
+ }
682
+ const response = await this.helpers.httpRequest({
683
+ method: 'POST',
684
+ url: `${baseUrl}/v1/marketplace/${operation}`,
685
+ headers: {
686
+ 'x-api-token': apiToken,
687
+ 'Content-Type': 'application/json',
688
+ },
689
+ body: params,
690
+ json: true,
691
+ });
692
+ if (response.success) {
693
+ if (Array.isArray(response.data)) {
694
+ for (const item of response.data) {
695
+ results.push({ json: item, pairedItem: { item: i } });
696
+ }
697
+ }
698
+ else {
699
+ results.push({ json: response.data, pairedItem: { item: i } });
700
+ }
701
+ }
702
+ else {
703
+ throw new Error(((_a = response.error) === null || _a === void 0 ? void 0 : _a.message) || 'Unknown error');
704
+ }
705
+ }
706
+ catch (error) {
707
+ if (this.continueOnFail()) {
708
+ results.push({
709
+ json: { error: error.message },
710
+ pairedItem: { item: i },
711
+ });
712
+ continue;
713
+ }
714
+ throw error;
715
+ }
716
+ }
717
+ return [results];
718
+ }
719
+ }
720
+ exports.SyncaMarketplace = SyncaMarketplace;
721
+ //# sourceMappingURL=SyncaMarketplace.node.js.map