n8n-nodes-aivencerealtycrm 1.6.0 → 1.8.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.
@@ -522,6 +522,12 @@ class AivenceRealty {
522
522
  },
523
523
  },
524
524
  options: [
525
+ {
526
+ name: 'Search',
527
+ value: 'search',
528
+ description: 'Buscar propiedades con filtros avanzados',
529
+ action: 'Buscar propiedades',
530
+ },
525
531
  {
526
532
  name: 'List',
527
533
  value: 'list',
@@ -595,6 +601,177 @@ class AivenceRealty {
595
601
  description: 'Búsqueda en lenguaje natural (ej: "Busco un apartamento de 3 dormitorios en Palermo con balcón")',
596
602
  },
597
603
  // ============================================
604
+ // PROPERTY SEARCH PARAMETERS
605
+ // ============================================
606
+ {
607
+ displayName: 'Property ID',
608
+ name: 'searchPropertyId',
609
+ type: 'number',
610
+ displayOptions: {
611
+ show: {
612
+ resource: ['property'],
613
+ operation: ['search'],
614
+ },
615
+ },
616
+ default: 0,
617
+ description: 'ID específico de la propiedad (opcional, deja en 0 para búsqueda por filtros)',
618
+ },
619
+ {
620
+ displayName: 'Operación',
621
+ name: 'searchOperacion',
622
+ type: 'options',
623
+ displayOptions: {
624
+ show: {
625
+ resource: ['property'],
626
+ operation: ['search'],
627
+ },
628
+ },
629
+ options: [
630
+ { name: 'Alquiler', value: 'Alquiler' },
631
+ { name: 'Compra', value: 'Compra' },
632
+ ],
633
+ default: '',
634
+ description: 'Tipo de operación inmobiliaria',
635
+ },
636
+ {
637
+ displayName: 'Tipo de Propiedad',
638
+ name: 'searchTipoPropiedad',
639
+ type: 'options',
640
+ displayOptions: {
641
+ show: {
642
+ resource: ['property'],
643
+ operation: ['search'],
644
+ },
645
+ },
646
+ options: [
647
+ { name: 'Casa', value: 'casa' },
648
+ { name: 'Apartamento', value: 'apartamento' },
649
+ { name: 'Departamento', value: 'apartamento' },
650
+ { name: 'Duplex', value: 'duplex' },
651
+ { name: 'PH', value: 'ph' },
652
+ { name: 'Local Comercial', value: 'local_comercial' },
653
+ { name: 'Oficina', value: 'oficina' },
654
+ { name: 'Terreno', value: 'terreno' },
655
+ { name: 'Bodega', value: 'bodega' },
656
+ { name: 'Quinta', value: 'quinta' },
657
+ { name: 'Cochera', value: 'cochera' },
658
+ ],
659
+ default: '',
660
+ description: 'Tipo de propiedad a buscar',
661
+ },
662
+ {
663
+ displayName: 'Zonas (Barrios)',
664
+ name: 'searchZonas',
665
+ type: 'string',
666
+ displayOptions: {
667
+ show: {
668
+ resource: ['property'],
669
+ operation: ['search'],
670
+ },
671
+ },
672
+ default: '',
673
+ placeholder: 'Núñez, Saavedra, Belgrano',
674
+ description: 'Zonas separadas por coma. Soporta Smart Zone Logic (1 zona = expandir, múltiples = respetar)',
675
+ },
676
+ {
677
+ displayName: 'Dormitorios Mínimo',
678
+ name: 'searchDormitoriosMin',
679
+ type: 'number',
680
+ displayOptions: {
681
+ show: {
682
+ resource: ['property'],
683
+ operation: ['search'],
684
+ },
685
+ },
686
+ default: 0,
687
+ description: 'Cantidad mínima de dormitorios',
688
+ },
689
+ {
690
+ displayName: 'Dormitorios Máximo',
691
+ name: 'searchDormitoriosMax',
692
+ type: 'number',
693
+ displayOptions: {
694
+ show: {
695
+ resource: ['property'],
696
+ operation: ['search'],
697
+ },
698
+ },
699
+ default: 0,
700
+ description: 'Cantidad máxima de dormitorios',
701
+ },
702
+ {
703
+ displayName: 'Baños',
704
+ name: 'searchBanos',
705
+ type: 'number',
706
+ displayOptions: {
707
+ show: {
708
+ resource: ['property'],
709
+ operation: ['search'],
710
+ },
711
+ },
712
+ default: 0,
713
+ description: 'Cantidad de baños',
714
+ },
715
+ {
716
+ displayName: 'Precio Mínimo',
717
+ name: 'searchPrecioMin',
718
+ type: 'number',
719
+ displayOptions: {
720
+ show: {
721
+ resource: ['property'],
722
+ operation: ['search'],
723
+ },
724
+ },
725
+ default: 0,
726
+ description: 'Precio mínimo en USD',
727
+ },
728
+ {
729
+ displayName: 'Precio Máximo',
730
+ name: 'searchPrecioMax',
731
+ type: 'number',
732
+ displayOptions: {
733
+ show: {
734
+ resource: ['property'],
735
+ operation: ['search'],
736
+ },
737
+ },
738
+ default: 0,
739
+ description: 'Precio máximo en USD',
740
+ },
741
+ {
742
+ displayName: 'Estado',
743
+ name: 'searchEstado',
744
+ type: 'options',
745
+ displayOptions: {
746
+ show: {
747
+ resource: ['property'],
748
+ operation: ['search'],
749
+ },
750
+ },
751
+ options: [
752
+ { name: 'Activo', value: 'activo' },
753
+ { name: 'Inactivo', value: 'inactivo' },
754
+ { name: 'Vendido', value: 'vendido' },
755
+ { name: 'Alquilado', value: 'alquilado' },
756
+ ],
757
+ default: 'activo',
758
+ description: 'Estado de la propiedad',
759
+ },
760
+ {
761
+ displayName: 'Amenidades',
762
+ name: 'searchAmenidades',
763
+ type: 'string',
764
+ displayOptions: {
765
+ show: {
766
+ resource: ['property'],
767
+ operation: ['search'],
768
+ },
769
+ },
770
+ default: '',
771
+ placeholder: 'Piscina, Gimnasio, Parrilla',
772
+ description: 'Amenidades separadas por coma',
773
+ },
774
+ // ============================================
598
775
  // EMAIL OPERATIONS
599
776
  // ============================================
600
777
  {
@@ -1606,7 +1783,72 @@ class AivenceRealty {
1606
1783
  // PROPERTY RESOURCE
1607
1784
  // ============================================
1608
1785
  else if (resource === 'property') {
1609
- if (operation === 'list') {
1786
+ if (operation === 'search') {
1787
+ // ============================================
1788
+ // PROPERTY SEARCH - Smart Zone Logic compatible
1789
+ // ============================================
1790
+ const qs = {};
1791
+ // Property ID (búsqueda directa por ID)
1792
+ const propertyId = this.getNodeParameter('searchPropertyId', i, 0);
1793
+ if (propertyId > 0) {
1794
+ qs.id = propertyId;
1795
+ }
1796
+ // Operación (Alquiler/Compra)
1797
+ const operacion = this.getNodeParameter('searchOperacion', i, '');
1798
+ if (operacion && operacion !== 'NULL' && operacion !== '') {
1799
+ qs.operacion = operacion;
1800
+ }
1801
+ // Tipo de Propiedad
1802
+ const tipoPropiedad = this.getNodeParameter('searchTipoPropiedad', i, '');
1803
+ if (tipoPropiedad && tipoPropiedad !== '' && tipoPropiedad !== 'NULL') {
1804
+ qs.tipo_propiedad = tipoPropiedad;
1805
+ }
1806
+ // Zonas (barrios) - Smart Zone Logic aplicado desde workflow
1807
+ const zonas = this.getNodeParameter('searchZonas', i, '');
1808
+ if (zonas && zonas !== '' && zonas !== 'NULL' && zonas !== 'null') {
1809
+ qs.barrio = zonas; // Formato: "Núñez, Saavedra, Belgrano"
1810
+ }
1811
+ // Dormitorios
1812
+ const dormitoriosMin = this.getNodeParameter('searchDormitoriosMin', i, 0);
1813
+ if (dormitoriosMin > 0) {
1814
+ qs.dormitorios_minimo = dormitoriosMin;
1815
+ }
1816
+ const dormitoriosMax = this.getNodeParameter('searchDormitoriosMax', i, 0);
1817
+ if (dormitoriosMax > 0) {
1818
+ qs.dormitorios_maximo = dormitoriosMax;
1819
+ }
1820
+ // Baños
1821
+ const banos = this.getNodeParameter('searchBanos', i, 0);
1822
+ if (banos > 0) {
1823
+ qs.banos = banos;
1824
+ }
1825
+ // Precio
1826
+ const precioMin = this.getNodeParameter('searchPrecioMin', i, 0);
1827
+ if (precioMin > 0) {
1828
+ qs.precio_minimo = precioMin;
1829
+ }
1830
+ const precioMax = this.getNodeParameter('searchPrecioMax', i, 0);
1831
+ if (precioMax > 0) {
1832
+ qs.precio_maximo = precioMax;
1833
+ }
1834
+ // Estado
1835
+ const estado = this.getNodeParameter('searchEstado', i, 'activo');
1836
+ if (estado && estado !== '') {
1837
+ qs.estado = estado;
1838
+ }
1839
+ // Amenidades
1840
+ const amenidades = this.getNodeParameter('searchAmenidades', i, '');
1841
+ if (amenidades && amenidades !== '' && amenidades !== 'NULL') {
1842
+ qs.amenidades = amenidades;
1843
+ }
1844
+ responseData = await this.helpers.httpRequest({
1845
+ method: 'GET',
1846
+ url: `${baseUrl}/api/v1/properties`,
1847
+ qs,
1848
+ json: true,
1849
+ });
1850
+ }
1851
+ else if (operation === 'list') {
1610
1852
  responseData = await this.helpers.httpRequest({
1611
1853
  method: 'GET',
1612
1854
  url: `${baseUrl}/api/v1/properties`,
@@ -1623,7 +1865,7 @@ class AivenceRealty {
1623
1865
  }
1624
1866
  else if (operation === 'getAgentView') {
1625
1867
  const propertyId = this.getNodeParameter('propertyId', i);
1626
- responseData = await this.helpers.httpRequest({
1868
+ responseData = await this.helpers.httpRequestWithAuthentication.call(this, 'aivenceRealtyApi', {
1627
1869
  method: 'GET',
1628
1870
  url: `${baseUrl}/api/v1/propiedades/agent/${propertyId}`,
1629
1871
  json: true,
@@ -66,6 +66,11 @@ class AivenceRealtyTrigger {
66
66
  value: 'maintenance.created',
67
67
  description: 'Se dispara cuando se crea una solicitud de mantenimiento',
68
68
  },
69
+ {
70
+ name: 'Contractor Response',
71
+ value: 'maintenance.contractor_response',
72
+ description: 'Se dispara cuando un contratista responde a una solicitud',
73
+ },
69
74
  {
70
75
  name: 'Appointment Creado',
71
76
  value: 'appointment.created',
@@ -0,0 +1,5 @@
1
+ import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
2
+ export declare class AivenceSocialMedia implements INodeType {
3
+ description: INodeTypeDescription;
4
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
+ }
@@ -0,0 +1,234 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AivenceSocialMedia = void 0;
4
+ class AivenceSocialMedia {
5
+ constructor() {
6
+ this.description = {
7
+ displayName: 'Aivence Social Media',
8
+ name: 'aivenceSocialMedia',
9
+ icon: 'file:aivencesocialmedia.png',
10
+ group: ['transform'],
11
+ version: 1,
12
+ subtitle: '={{$parameter["operation"]}}',
13
+ description: 'Gestión de publicaciones en redes sociales con Postiz',
14
+ defaults: {
15
+ name: 'Aivence Social Media',
16
+ },
17
+ inputs: ['main'],
18
+ outputs: ['main'],
19
+ credentials: [
20
+ {
21
+ name: 'aivenceRealtyApi',
22
+ required: true,
23
+ },
24
+ ],
25
+ properties: [
26
+ // ============================================
27
+ // OPERATION SELECTOR
28
+ // ============================================
29
+ {
30
+ displayName: 'Operación',
31
+ name: 'operation',
32
+ type: 'options',
33
+ noDataExpression: true,
34
+ options: [
35
+ {
36
+ name: 'Create Carousel Post',
37
+ value: 'createCarousel',
38
+ description: 'Crear post carrusel programado en Instagram + Facebook',
39
+ action: 'Crear carrusel en redes sociales',
40
+ },
41
+ ],
42
+ default: 'createCarousel',
43
+ description: 'Operación a realizar',
44
+ },
45
+ // ============================================
46
+ // CAROUSEL POST FIELDS
47
+ // ============================================
48
+ {
49
+ displayName: 'Image URLs',
50
+ name: 'imageUrls',
51
+ type: 'string',
52
+ typeOptions: {
53
+ multipleValues: true,
54
+ multipleValueButtonText: 'Agregar imagen',
55
+ },
56
+ displayOptions: {
57
+ show: {
58
+ operation: ['createCarousel'],
59
+ },
60
+ },
61
+ default: [],
62
+ required: true,
63
+ description: 'URLs de las imágenes para el carrusel (máximo 10)',
64
+ placeholder: 'https://example.com/image1.jpg',
65
+ },
66
+ {
67
+ displayName: 'Caption',
68
+ name: 'caption',
69
+ type: 'string',
70
+ typeOptions: {
71
+ rows: 4,
72
+ },
73
+ displayOptions: {
74
+ show: {
75
+ operation: ['createCarousel'],
76
+ },
77
+ },
78
+ default: '',
79
+ required: true,
80
+ description: 'Texto del post (caption) para las redes sociales',
81
+ placeholder: '🏠 Nueva propiedad disponible...',
82
+ },
83
+ {
84
+ displayName: 'Schedule Hours Ahead',
85
+ name: 'scheduleHours',
86
+ type: 'number',
87
+ displayOptions: {
88
+ show: {
89
+ operation: ['createCarousel'],
90
+ },
91
+ },
92
+ default: 4,
93
+ required: true,
94
+ description: 'Horas desde ahora para programar la publicación',
95
+ typeOptions: {
96
+ minValue: 1,
97
+ maxValue: 168,
98
+ },
99
+ },
100
+ {
101
+ displayName: 'Instagram Integration ID',
102
+ name: 'instagramIntegrationId',
103
+ type: 'string',
104
+ displayOptions: {
105
+ show: {
106
+ operation: ['createCarousel'],
107
+ },
108
+ },
109
+ default: '',
110
+ required: true,
111
+ description: 'ID de la integración de Instagram en Postiz',
112
+ placeholder: 'instagram_channel_id',
113
+ },
114
+ {
115
+ displayName: 'Facebook Integration ID',
116
+ name: 'facebookIntegrationId',
117
+ type: 'string',
118
+ displayOptions: {
119
+ show: {
120
+ operation: ['createCarousel'],
121
+ },
122
+ },
123
+ default: '',
124
+ required: true,
125
+ description: 'ID de la integración de Facebook en Postiz',
126
+ placeholder: 'facebook_page_id',
127
+ },
128
+ {
129
+ displayName: 'Agent User ID',
130
+ name: 'agentUserId',
131
+ type: 'number',
132
+ displayOptions: {
133
+ show: {
134
+ operation: ['createCarousel'],
135
+ },
136
+ },
137
+ default: 5,
138
+ required: true,
139
+ description: 'ID del agente inmobiliario para notificar (default: Carlos Rodriguez = 5)',
140
+ },
141
+ {
142
+ displayName: 'Property Data',
143
+ name: 'propertyData',
144
+ type: 'json',
145
+ displayOptions: {
146
+ show: {
147
+ operation: ['createCarousel'],
148
+ },
149
+ },
150
+ default: '{}',
151
+ description: 'Datos adicionales de la propiedad (opcional, en formato JSON)',
152
+ placeholder: '{"property_id": 123, "title": "Casa en venta"}',
153
+ },
154
+ ],
155
+ };
156
+ }
157
+ async execute() {
158
+ const items = this.getInputData();
159
+ const returnData = [];
160
+ const credentials = await this.getCredentials('aivenceRealtyApi');
161
+ const baseUrl = credentials.url.replace(/\/$/, '');
162
+ for (let i = 0; i < items.length; i++) {
163
+ try {
164
+ const operation = this.getNodeParameter('operation', i);
165
+ let responseData = {};
166
+ if (operation === 'createCarousel') {
167
+ // Get parameters
168
+ const imageUrls = this.getNodeParameter('imageUrls', i);
169
+ const caption = this.getNodeParameter('caption', i);
170
+ const scheduleHours = this.getNodeParameter('scheduleHours', i);
171
+ const instagramIntegrationId = this.getNodeParameter('instagramIntegrationId', i);
172
+ const facebookIntegrationId = this.getNodeParameter('facebookIntegrationId', i);
173
+ const agentUserId = this.getNodeParameter('agentUserId', i);
174
+ const propertyDataStr = this.getNodeParameter('propertyData', i, '{}');
175
+ // Parse property data
176
+ let propertyData = {};
177
+ try {
178
+ propertyData = JSON.parse(propertyDataStr);
179
+ }
180
+ catch (error) {
181
+ propertyData = {};
182
+ }
183
+ // Validate image count
184
+ if (imageUrls.length === 0) {
185
+ throw new Error('Debes proporcionar al menos 1 imagen');
186
+ }
187
+ if (imageUrls.length > 10) {
188
+ throw new Error('Máximo 10 imágenes permitidas en un carrusel');
189
+ }
190
+ // Calculate schedule time (ISO 8601 format)
191
+ const scheduledDate = new Date();
192
+ scheduledDate.setHours(scheduledDate.getHours() + scheduleHours);
193
+ const scheduledDateISO = scheduledDate.toISOString();
194
+ // Prepare request body
195
+ const requestBody = {
196
+ imageUrls,
197
+ caption,
198
+ scheduleDate: scheduledDateISO,
199
+ instagramIntegrationId,
200
+ facebookIntegrationId,
201
+ agentUserId,
202
+ propertyData,
203
+ };
204
+ // Make API request to AivenceRealty backend
205
+ responseData = await this.helpers.httpRequest({
206
+ method: 'POST',
207
+ url: `${baseUrl}/api/v1/social-media/create-carousel`,
208
+ body: requestBody,
209
+ json: true,
210
+ headers: {
211
+ 'Content-Type': 'application/json',
212
+ },
213
+ });
214
+ }
215
+ // Format response
216
+ const executionData = this.helpers.constructExecutionMetaData(this.helpers.returnJsonArray(responseData), { itemData: { item: i } });
217
+ returnData.push(...executionData);
218
+ }
219
+ catch (error) {
220
+ if (this.continueOnFail()) {
221
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
222
+ returnData.push({
223
+ json: { error: errorMessage },
224
+ pairedItem: { item: i },
225
+ });
226
+ continue;
227
+ }
228
+ throw error;
229
+ }
230
+ }
231
+ return [returnData];
232
+ }
233
+ }
234
+ exports.AivenceSocialMedia = AivenceSocialMedia;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-aivencerealtycrm",
3
- "version": "1.6.0",
3
+ "version": "1.8.0",
4
4
  "description": "Nodo n8n para integrar el CRM inmobiliario AivenceRealty",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",
@@ -41,7 +41,8 @@
41
41
  ],
42
42
  "nodes": [
43
43
  "dist/nodes/AivenceRealty/AivenceRealty.node.js",
44
- "dist/nodes/AivenceRealtyTrigger/AivenceRealtyTrigger.node.js"
44
+ "dist/nodes/AivenceRealtyTrigger/AivenceRealtyTrigger.node.js",
45
+ "dist/nodes/AivenceSocialMedia/AivenceSocialMedia.node.js"
45
46
  ]
46
47
  },
47
48
  "devDependencies": {