n8n-nodes-prestashop8 1.2.0 → 1.2.2

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.
@@ -154,16 +154,23 @@ exports.PrestaShop8Description = {
154
154
  placeholder: '[id_DESC] ou [name_ASC]',
155
155
  description: 'Sort criteria (e.g. [id_DESC], [name_ASC], [date_add_DESC])',
156
156
  },
157
+ {
158
+ displayName: 'Date Format',
159
+ name: 'dateFormat',
160
+ type: 'boolean',
161
+ default: false,
162
+ description: 'Enable date processing in filters (adds date=1 parameter)',
163
+ },
157
164
  ],
158
165
  },
159
- // Display options (always visible for list/search operations)
166
+ // Display options (always visible for list/search/getById operations)
160
167
  {
161
168
  displayName: 'Display',
162
169
  name: 'display',
163
170
  type: 'options',
164
171
  displayOptions: {
165
172
  show: {
166
- operation: ['list', 'search'],
173
+ operation: ['list', 'search', 'getById'],
167
174
  },
168
175
  },
169
176
  options: [
@@ -193,7 +200,7 @@ exports.PrestaShop8Description = {
193
200
  type: 'string',
194
201
  displayOptions: {
195
202
  show: {
196
- operation: ['list', 'search'],
203
+ operation: ['list', 'search', 'getById'],
197
204
  display: ['custom'],
198
205
  },
199
206
  },
@@ -226,9 +233,13 @@ exports.PrestaShop8Description = {
226
233
  name: 'field',
227
234
  type: 'string',
228
235
  default: '',
229
- required: true,
230
236
  placeholder: 'name, reference, price, etc.',
231
237
  description: 'Name of field to filter. Examples: name, reference, price, active, id_manufacturer, etc.',
238
+ displayOptions: {
239
+ hide: {
240
+ operator: ['CUSTOM'],
241
+ },
242
+ },
232
243
  },
233
244
  {
234
245
  displayName: 'Operator',
@@ -237,16 +248,33 @@ exports.PrestaShop8Description = {
237
248
  options: types_1.FILTER_OPERATORS,
238
249
  default: '=',
239
250
  noDataExpression: true,
240
- description: 'Comparison operator for filtering. Available operators: = (exact match), LIKE (contains text), > (greater than), >= (greater or equal), < (less than), <= (less or equal), != (not equal), BEGINS (starts with), ENDS (ends with)',
251
+ description: 'Comparison operator for filtering. Custom allows you to write your own filter expression.',
241
252
  },
242
253
  {
243
254
  displayName: 'Value',
244
255
  name: 'value',
245
256
  type: 'string',
246
257
  default: '',
247
- required: true,
248
- placeholder: 'search value',
249
- description: 'Value to search for. Examples: "Product Name" (for LIKE), "1" (for active), "29.99" (for price), etc.',
258
+ placeholder: 'search value or interval',
259
+ description: 'Value to search for. Examples: "Product Name", "1" (active), "29.99" (price). For Equal/Not Equal: use "10,20" for intervals (becomes [10,20]).',
260
+ displayOptions: {
261
+ hide: {
262
+ operator: ['IS_EMPTY', 'IS_NOT_EMPTY', 'CUSTOM'],
263
+ },
264
+ },
265
+ },
266
+ {
267
+ displayName: 'Custom Filter Expression',
268
+ name: 'customFilter',
269
+ type: 'string',
270
+ default: '',
271
+ placeholder: 'filter[name]=[Product]%',
272
+ description: 'Complete filter expression in PrestaShop format. Example: filter[name]=[Product]%, filter[price]=>[100], etc.',
273
+ displayOptions: {
274
+ show: {
275
+ operator: ['CUSTOM'],
276
+ },
277
+ },
250
278
  },
251
279
  ],
252
280
  },
@@ -311,12 +311,20 @@ class PrestaShop8 {
311
311
  const advancedOptions = this.getNodeParameter('advancedOptions', i, {});
312
312
  const display = this.getNodeParameter('display', i, 'full');
313
313
  const customFields = this.getNodeParameter('customFields', i, '');
314
- const displayValue = display === 'custom' ? customFields : display;
315
- requestUrl = (0, utils_1.buildUrlWithFilters)(`${credentials.baseUrl}/${resource}`, {
314
+ const displayValue = (0, utils_1.processDisplayParameter)(display, resource, customFields);
315
+ const urlParams = {
316
316
  limit: advancedOptions.limit,
317
317
  sort: advancedOptions.sort,
318
- display: displayValue,
319
- }, rawMode);
318
+ };
319
+ // Add date=1 parameter if Date Format option is enabled
320
+ if (advancedOptions.dateFormat) {
321
+ urlParams.date = 1;
322
+ }
323
+ // Only add display parameter if not null (minimal mode returns null)
324
+ if (displayValue !== null) {
325
+ urlParams.display = displayValue;
326
+ }
327
+ requestUrl = (0, utils_1.buildUrlWithFilters)(`${credentials.baseUrl}/${resource}`, urlParams, rawMode);
320
328
  const timeout = this.getNodeParameter('options.timeout', i, 30000);
321
329
  const neverError = this.getNodeParameter('options.response.neverError', i, false);
322
330
  const includeResponseHeaders = this.getNodeParameter('options.response.includeResponseHeaders', i, false);
@@ -402,13 +410,18 @@ class PrestaShop8 {
402
410
  }
403
411
  case 'getById': {
404
412
  const id = this.getNodeParameter('id', i);
405
- const advancedOptions = this.getNodeParameter('advancedOptions', i, {});
413
+ const display = this.getNodeParameter('display', i, 'full');
414
+ const customFields = this.getNodeParameter('customFields', i, '');
406
415
  if (!id) {
407
416
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'ID required for this operation');
408
417
  }
409
- requestUrl = (0, utils_1.buildUrlWithFilters)(`${credentials.baseUrl}/${resource}/${id}`, {
410
- display: advancedOptions.display === 'custom' ? advancedOptions.customFields : advancedOptions.display,
411
- }, rawMode);
418
+ const displayValue = (0, utils_1.processDisplayParameter)(display, resource, customFields);
419
+ const urlParams = {};
420
+ // Only add display parameter if not null (minimal mode returns null)
421
+ if (displayValue !== null) {
422
+ urlParams.display = displayValue;
423
+ }
424
+ requestUrl = (0, utils_1.buildUrlWithFilters)(`${credentials.baseUrl}/${resource}/${id}`, urlParams, rawMode);
412
425
  const timeout = this.getNodeParameter('options.timeout', i, 30000);
413
426
  const neverError = this.getNodeParameter('options.response.neverError', i, false);
414
427
  const includeResponseHeaders = this.getNodeParameter('options.response.includeResponseHeaders', i, false);
@@ -537,6 +550,11 @@ class PrestaShop8 {
537
550
  const advancedOptions = this.getNodeParameter('advancedOptions', i, {});
538
551
  const display = this.getNodeParameter('display', i, 'full');
539
552
  const customFields = this.getNodeParameter('customFields', i, '');
553
+ // Debug: Log the filters parameter structure
554
+ const showRequestInfo = this.getNodeParameter('options.request.showRequestInfo', i, false);
555
+ if (showRequestInfo) {
556
+ console.log('DEBUG - filtersParam:', JSON.stringify(filtersParam, null, 2));
557
+ }
540
558
  const filters = filtersParam.filter || [];
541
559
  if (!filters.length) {
542
560
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'At least one filter is required for search');
@@ -544,38 +562,123 @@ class PrestaShop8 {
544
562
  // Build filter parameters for URL
545
563
  const filterParams = {};
546
564
  for (const filter of filters) {
547
- if (filter.value && filter.value.trim()) {
548
- const key = `filter[${filter.field}]`;
549
- // Handle different operators
550
- switch (filter.operator) {
551
- case 'equals':
552
- filterParams[key] = `[${filter.value}]`;
553
- break;
554
- case 'contains':
555
- filterParams[key] = `[${filter.value}]%`;
556
- break;
557
- case 'starts_with':
565
+ if (showRequestInfo) {
566
+ console.log('DEBUG - Processing filter:', JSON.stringify(filter, null, 2));
567
+ }
568
+ // Handle CUSTOM filter operator
569
+ if (filter.operator === 'CUSTOM') {
570
+ if (filter.customFilter && filter.customFilter.trim()) {
571
+ // Add custom filter directly to URL without any interpretation
572
+ // User writes exactly what they want: date=1, filter[name]=test, etc.
573
+ const customFilter = filter.customFilter.trim();
574
+ // Parse the custom filter to extract key=value pairs for URL construction
575
+ const parts = customFilter.split('&');
576
+ for (const part of parts) {
577
+ const [key, value] = part.split('=', 2);
578
+ if (key && value !== undefined) {
579
+ filterParams[key.trim()] = value.trim();
580
+ }
581
+ }
582
+ }
583
+ continue;
584
+ }
585
+ const key = `filter[${filter.field}]`;
586
+ // Handle different operators with correct PrestaShop formats
587
+ switch (filter.operator) {
588
+ case '=':
589
+ if (filter.value && filter.value.trim()) {
590
+ const value = filter.value.trim();
591
+ // Check if value contains comma for interval (e.g., "10,20" → "[10,20]")
592
+ if (value.includes(',') && !value.startsWith('[')) {
593
+ filterParams[key] = `[${value}]`;
594
+ }
595
+ else {
596
+ filterParams[key] = `[${value}]`;
597
+ }
598
+ }
599
+ break;
600
+ case '!=':
601
+ if (filter.value && filter.value.trim()) {
602
+ const value = filter.value.trim();
603
+ // Check if value contains comma for interval (e.g., "10,20" → "![10,20]")
604
+ if (value.includes(',') && !value.startsWith('[')) {
605
+ filterParams[key] = `![${value}]`;
606
+ }
607
+ else {
608
+ filterParams[key] = `![${value}]`;
609
+ }
610
+ }
611
+ break;
612
+ case '>':
613
+ if (filter.value && filter.value.trim()) {
614
+ filterParams[key] = `>[${filter.value}]`;
615
+ }
616
+ break;
617
+ case '>=':
618
+ if (filter.value && filter.value.trim()) {
619
+ filterParams[key] = `>=[${filter.value}]`;
620
+ }
621
+ break;
622
+ case '<':
623
+ if (filter.value && filter.value.trim()) {
624
+ filterParams[key] = `<[${filter.value}]`;
625
+ }
626
+ break;
627
+ case '<=':
628
+ if (filter.value && filter.value.trim()) {
629
+ filterParams[key] = `<=[${filter.value}]`;
630
+ }
631
+ break;
632
+ case 'CONTAINS':
633
+ if (filter.value && filter.value.trim()) {
634
+ filterParams[key] = `%[${filter.value}]%`;
635
+ }
636
+ break;
637
+ case 'BEGINS':
638
+ if (filter.value && filter.value.trim()) {
558
639
  filterParams[key] = `[${filter.value}]%`;
559
- break;
560
- case 'greater_than':
561
- filterParams[key] = `[${filter.value},]`;
562
- break;
563
- case 'less_than':
564
- filterParams[key] = `[,${filter.value}]`;
565
- break;
566
- default:
640
+ }
641
+ break;
642
+ case 'ENDS':
643
+ if (filter.value && filter.value.trim()) {
644
+ filterParams[key] = `%[${filter.value}]`;
645
+ }
646
+ break;
647
+ case 'IS_EMPTY':
648
+ filterParams[key] = `[]`;
649
+ break;
650
+ case 'IS_NOT_EMPTY':
651
+ filterParams[key] = `![]`;
652
+ break;
653
+ default:
654
+ if (filter.value && filter.value.trim()) {
567
655
  filterParams[key] = `[${filter.value}]`;
568
- }
656
+ }
569
657
  }
570
658
  }
571
659
  // Handle display parameter
572
660
  const displayValue = (0, utils_1.processDisplayParameter)(display, resource, customFields);
573
- requestUrl = (0, utils_1.buildUrlWithFilters)(`${credentials.baseUrl}/${resource}`, {
661
+ const urlParams = {
574
662
  ...filterParams,
575
663
  limit: advancedOptions.limit,
576
664
  sort: advancedOptions.sort,
577
- display: displayValue,
578
- }, rawMode);
665
+ };
666
+ // Add date=1 parameter if Date Format option is enabled
667
+ if (advancedOptions.dateFormat) {
668
+ urlParams.date = 1;
669
+ }
670
+ // Only add display parameter if not null (minimal mode returns null)
671
+ if (displayValue !== null) {
672
+ urlParams.display = displayValue;
673
+ }
674
+ if (showRequestInfo) {
675
+ console.log('DEBUG - Final filterParams:', JSON.stringify(filterParams, null, 2));
676
+ console.log('DEBUG - Final urlParams:', JSON.stringify(urlParams, null, 2));
677
+ }
678
+ requestUrl = (0, utils_1.buildUrlWithFilters)(`${credentials.baseUrl}/${resource}`, urlParams, rawMode);
679
+ if (showRequestInfo) {
680
+ console.log('DEBUG - Final URL:', requestUrl);
681
+ }
579
682
  const timeout = this.getNodeParameter('options.timeout', i, 30000);
580
683
  const neverError = this.getNodeParameter('options.response.neverError', i, false);
581
684
  const includeResponseHeaders = this.getNodeParameter('options.response.includeResponseHeaders', i, false);
@@ -6,6 +6,7 @@ export interface IPrestaShopFilter {
6
6
  field: string;
7
7
  operator: string;
8
8
  value: string;
9
+ customFilter?: string;
9
10
  }
10
11
  export interface IPrestaShopRequestOptions {
11
12
  resource: string;
@@ -360,8 +360,10 @@ exports.FILTER_OPERATORS = [
360
360
  { name: '≥ Greater than or equal to', value: '>=' },
361
361
  { name: '< Less than', value: '<' },
362
362
  { name: '≤ Less than or equal to', value: '<=' },
363
- { name: '∋ Contains', value: 'LIKE' },
364
- { name: '∌ Does not contain', value: 'NOT LIKE' },
363
+ { name: '∋ Contains', value: 'CONTAINS' },
365
364
  { name: '↦ Starts with', value: 'BEGINS' },
366
365
  { name: '↤ Ends with', value: 'ENDS' },
366
+ { name: '∅ Is Empty', value: 'IS_EMPTY' },
367
+ { name: '∄ Is not Empty', value: 'IS_NOT_EMPTY' },
368
+ { name: '⚙️ Custom Filter', value: 'CUSTOM' },
367
369
  ];
@@ -429,30 +429,21 @@ exports.parseXmlToJson = parseXmlToJson;
429
429
  function buildUrlWithFilters(baseUrl, options, rawMode) {
430
430
  const url = new URL(baseUrl);
431
431
  const params = new URLSearchParams();
432
- // Ajouter les filtres
433
- if (options.filters && Array.isArray(options.filters)) {
434
- for (const filter of options.filters) {
435
- if (filter.field && filter.value) {
436
- const filterKey = `filter[${filter.field}]`;
437
- let filterValue = filter.value;
438
- // Apply operator if it's not '='
439
- if (filter.operator && filter.operator !== '=') {
440
- filterValue = `[${filter.operator}]${filterValue}`;
441
- }
442
- params.append(filterKey, filterValue);
432
+ // Add all parameters from options object
433
+ for (const [key, value] of Object.entries(options)) {
434
+ if (value !== null && value !== undefined && value !== '') {
435
+ if (key === 'sort') {
436
+ // Special handling for sort parameter
437
+ const normalizedSort = processSortParameter(String(value));
438
+ if (normalizedSort)
439
+ params.append('sort', normalizedSort);
440
+ }
441
+ else {
442
+ // Add all other parameters as-is (including custom user parameters)
443
+ params.append(key, String(value));
443
444
  }
444
445
  }
445
446
  }
446
- // Add other parameters
447
- if (options.limit)
448
- params.append('limit', options.limit);
449
- if (options.sort) {
450
- const normalizedSort = processSortParameter(options.sort);
451
- if (normalizedSort)
452
- params.append('sort', normalizedSort);
453
- }
454
- if (options.display !== null && options.display !== undefined)
455
- params.append('display', options.display);
456
447
  // Ajouter output_format seulement si pas en mode Raw
457
448
  if (!rawMode) {
458
449
  params.append('output_format', 'JSON');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-prestashop8",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "Nœud n8n personnalisé pour PrestaShop 8 avec support CRUD complet et conversion XML/JSON automatique",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",