n8n-nodes-aivence-realty 0.1.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/README.md +127 -0
- package/dist/credentials/AivenceRealtyApi.credentials.d.ts +9 -0
- package/dist/credentials/AivenceRealtyApi.credentials.js +46 -0
- package/dist/nodes/AivenceRealty/AivenceRealty.node.d.ts +5 -0
- package/dist/nodes/AivenceRealty/AivenceRealty.node.js +777 -0
- package/dist/nodes/AivenceRealty/aivencerealty.png +0 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# n8n-nodes-aivence-realty
|
|
2
|
+
|
|
3
|
+
**Nodo n8n para AivenceRealty CRM (Laravel).**
|
|
4
|
+
|
|
5
|
+
Este paquete añade nodos para interactuar con el CRM inmobiliario AivenceRealty. Permite operaciones completas sobre Properties, Leads, Maintenance Orders, Contractors, y más.
|
|
6
|
+
|
|
7
|
+
## 📦 Instalación
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install n8n-nodes-aivence-realty
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
O desde la interfaz de n8n: **Community Nodes → Install** y escribir `n8n-nodes-aivence-realty`.
|
|
14
|
+
|
|
15
|
+
## 🔐 Configuración
|
|
16
|
+
|
|
17
|
+
1. Obtén un **Bearer Token** desde tu panel de AivenceRealty
|
|
18
|
+
2. En n8n, ve a **Credentials** y crea credenciales de tipo **AivenceRealty API**
|
|
19
|
+
3. Introduce:
|
|
20
|
+
- **URL Base**: `https://realty.aivence.com` (o tu dominio)
|
|
21
|
+
- **Bearer Token**: Tu token de API
|
|
22
|
+
4. Guarda las credenciales
|
|
23
|
+
|
|
24
|
+
## 📋 Recursos Disponibles
|
|
25
|
+
|
|
26
|
+
### 1. **Property** (Propiedades)
|
|
27
|
+
- `list` - Listar todas las propiedades
|
|
28
|
+
- `getSimilar` - Obtener propiedades similares
|
|
29
|
+
- `getStatistics` - Estadísticas de propiedades
|
|
30
|
+
|
|
31
|
+
### 2. **Lead** (Leads)
|
|
32
|
+
- `list` - Listar leads
|
|
33
|
+
- `create` - Crear nuevo lead (campos: nombre, telefono, mensaje)
|
|
34
|
+
|
|
35
|
+
### 3. **Tenant** (Inquilinos)
|
|
36
|
+
- `list` - Listar inquilinos
|
|
37
|
+
|
|
38
|
+
### 4. **Maintenance Order** (Órdenes de Mantenimiento)
|
|
39
|
+
- `checkDuplicate` - Verificar si existe orden duplicada
|
|
40
|
+
- `create` - Crear nueva orden
|
|
41
|
+
- `get` - Obtener orden por ID
|
|
42
|
+
- `update` - Actualizar orden
|
|
43
|
+
- `list` - Listar órdenes
|
|
44
|
+
|
|
45
|
+
### 5. **Contractor** (Contratistas)
|
|
46
|
+
- `findByCategory` - Buscar por categoría (fontanería, electricidad, etc.)
|
|
47
|
+
- `findAlternatives` - Buscar contratistas alternativos
|
|
48
|
+
|
|
49
|
+
### 6. **Monthly Cost** (Costos Mensuales)
|
|
50
|
+
- `track` - Registrar costo mensual
|
|
51
|
+
|
|
52
|
+
### 7. **WhatsApp**
|
|
53
|
+
- `sendMessage` - Enviar mensaje por WhatsApp (Evolution API)
|
|
54
|
+
|
|
55
|
+
## 🎯 Ejemplos de Uso
|
|
56
|
+
|
|
57
|
+
### Crear un Lead
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"resource": "lead",
|
|
62
|
+
"operation": "create",
|
|
63
|
+
"nombre": "Juan Pérez",
|
|
64
|
+
"telefono": "5491112345678",
|
|
65
|
+
"mensaje": "Busco departamento 2 ambientes en Palermo"
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Crear Orden de Mantenimiento
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"resource": "maintenanceOrder",
|
|
74
|
+
"operation": "create",
|
|
75
|
+
"clienteId": 123,
|
|
76
|
+
"propiedadId": 456,
|
|
77
|
+
"contratistaId": 789,
|
|
78
|
+
"categoria": "fontanería",
|
|
79
|
+
"urgencia": "alta",
|
|
80
|
+
"descripcionCorta": "Fuga de agua",
|
|
81
|
+
"descripcionDetallada": "Fuga en baño principal..."
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## 🔧 Desarrollo Local
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# Clonar repositorio
|
|
89
|
+
git clone https://github.com/aivence/n8n-nodes-aivence-realty.git
|
|
90
|
+
cd n8n-nodes-aivence-realty
|
|
91
|
+
|
|
92
|
+
# Instalar dependencias
|
|
93
|
+
npm install
|
|
94
|
+
|
|
95
|
+
# Compilar
|
|
96
|
+
npm run build
|
|
97
|
+
|
|
98
|
+
# Vincular localmente
|
|
99
|
+
npm link
|
|
100
|
+
cd ~/.n8n
|
|
101
|
+
npm link n8n-nodes-aivence-realty
|
|
102
|
+
|
|
103
|
+
# Iniciar n8n
|
|
104
|
+
n8n start
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## 📝 Changelog
|
|
108
|
+
|
|
109
|
+
### v0.1.0 (2025-10-09)
|
|
110
|
+
- 🎉 Versión inicial
|
|
111
|
+
- ✅ 7 recursos implementados
|
|
112
|
+
- ✅ 15 operaciones totales
|
|
113
|
+
- ✅ Integración completa con API Laravel
|
|
114
|
+
|
|
115
|
+
## 📄 Licencia
|
|
116
|
+
|
|
117
|
+
MIT
|
|
118
|
+
|
|
119
|
+
## 👨💻 Autor
|
|
120
|
+
|
|
121
|
+
**Federico Aivence** - [federico@aivence.com](mailto:federico@aivence.com)
|
|
122
|
+
|
|
123
|
+
## 🔗 Links
|
|
124
|
+
|
|
125
|
+
- [AivenceRealty CRM](https://realty.aivence.com)
|
|
126
|
+
- [Repositorio GitHub](https://github.com/aivence/n8n-nodes-aivence-realty)
|
|
127
|
+
- [Reportar Issues](https://github.com/aivence/n8n-nodes-aivence-realty/issues)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { IAuthenticateGeneric, ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
|
|
2
|
+
export declare class AivenceRealtyApi implements ICredentialType {
|
|
3
|
+
name: string;
|
|
4
|
+
displayName: string;
|
|
5
|
+
documentationUrl: string;
|
|
6
|
+
properties: INodeProperties[];
|
|
7
|
+
authenticate: IAuthenticateGeneric;
|
|
8
|
+
test: ICredentialTestRequest;
|
|
9
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AivenceRealtyApi = void 0;
|
|
4
|
+
class AivenceRealtyApi {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.name = 'aivenceRealtyApi';
|
|
7
|
+
this.displayName = 'AivenceRealty API';
|
|
8
|
+
this.documentationUrl = 'https://realty.aivence.com/api-docs';
|
|
9
|
+
this.properties = [
|
|
10
|
+
{
|
|
11
|
+
displayName: 'URL Base',
|
|
12
|
+
name: 'baseUrl',
|
|
13
|
+
type: 'string',
|
|
14
|
+
default: 'https://realty.aivence.com',
|
|
15
|
+
description: 'URL base de la API de AivenceRealty',
|
|
16
|
+
required: true,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
displayName: 'Bearer Token',
|
|
20
|
+
name: 'apiKey',
|
|
21
|
+
type: 'string',
|
|
22
|
+
typeOptions: { password: true },
|
|
23
|
+
default: '',
|
|
24
|
+
description: 'Token de autorización Bearer para la API',
|
|
25
|
+
required: true,
|
|
26
|
+
},
|
|
27
|
+
];
|
|
28
|
+
this.authenticate = {
|
|
29
|
+
type: 'generic',
|
|
30
|
+
properties: {
|
|
31
|
+
headers: {
|
|
32
|
+
'Authorization': '=Bearer {{$credentials.apiKey}}',
|
|
33
|
+
'Accept': 'application/json',
|
|
34
|
+
'Content-Type': 'application/json',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
this.test = {
|
|
39
|
+
request: {
|
|
40
|
+
baseURL: '={{$credentials.baseUrl}}',
|
|
41
|
+
url: '/api/health',
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.AivenceRealtyApi = AivenceRealtyApi;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
|
|
2
|
+
export declare class AivenceRealty implements INodeType {
|
|
3
|
+
description: INodeTypeDescription;
|
|
4
|
+
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
5
|
+
}
|
|
@@ -0,0 +1,777 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AivenceRealty = void 0;
|
|
4
|
+
class AivenceRealty {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.description = {
|
|
7
|
+
displayName: 'AivenceRealty CRM',
|
|
8
|
+
name: 'aivenceRealty',
|
|
9
|
+
icon: 'file:aivencerealty.png',
|
|
10
|
+
group: ['transform'],
|
|
11
|
+
version: 1,
|
|
12
|
+
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
|
13
|
+
description: 'Integración con AivenceRealty CRM Inmobiliario',
|
|
14
|
+
defaults: {
|
|
15
|
+
name: 'AivenceRealty CRM',
|
|
16
|
+
},
|
|
17
|
+
inputs: ['main'],
|
|
18
|
+
outputs: ['main'],
|
|
19
|
+
credentials: [
|
|
20
|
+
{
|
|
21
|
+
name: 'aivenceRealtyApi',
|
|
22
|
+
required: true,
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
properties: [
|
|
26
|
+
// ============================================
|
|
27
|
+
// RESOURCE SELECTOR
|
|
28
|
+
// ============================================
|
|
29
|
+
{
|
|
30
|
+
displayName: 'Recurso',
|
|
31
|
+
name: 'resource',
|
|
32
|
+
type: 'options',
|
|
33
|
+
noDataExpression: true,
|
|
34
|
+
options: [
|
|
35
|
+
{
|
|
36
|
+
name: 'Property',
|
|
37
|
+
value: 'property',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: 'Lead',
|
|
41
|
+
value: 'lead',
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: 'Tenant',
|
|
45
|
+
value: 'tenant',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: 'Maintenance Order',
|
|
49
|
+
value: 'maintenanceOrder',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: 'Contractor',
|
|
53
|
+
value: 'contractor',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: 'Monthly Cost',
|
|
57
|
+
value: 'monthlyCost',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: 'WhatsApp',
|
|
61
|
+
value: 'whatsapp',
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
default: 'property',
|
|
65
|
+
description: 'Recurso del CRM a operar',
|
|
66
|
+
},
|
|
67
|
+
// ============================================
|
|
68
|
+
// PROPERTY OPERATIONS
|
|
69
|
+
// ============================================
|
|
70
|
+
{
|
|
71
|
+
displayName: 'Operación',
|
|
72
|
+
name: 'operation',
|
|
73
|
+
type: 'options',
|
|
74
|
+
noDataExpression: true,
|
|
75
|
+
displayOptions: {
|
|
76
|
+
show: {
|
|
77
|
+
resource: ['property'],
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
options: [
|
|
81
|
+
{
|
|
82
|
+
name: 'List',
|
|
83
|
+
value: 'list',
|
|
84
|
+
description: 'Listar todas las propiedades',
|
|
85
|
+
action: 'Listar propiedades',
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: 'Get Similar',
|
|
89
|
+
value: 'getSimilar',
|
|
90
|
+
description: 'Obtener propiedades similares',
|
|
91
|
+
action: 'Obtener propiedades similares',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: 'Get Statistics',
|
|
95
|
+
value: 'getStatistics',
|
|
96
|
+
description: 'Obtener estadísticas de propiedades',
|
|
97
|
+
action: 'Obtener estadísticas',
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
default: 'list',
|
|
101
|
+
},
|
|
102
|
+
// ============================================
|
|
103
|
+
// LEAD OPERATIONS
|
|
104
|
+
// ============================================
|
|
105
|
+
{
|
|
106
|
+
displayName: 'Operación',
|
|
107
|
+
name: 'operation',
|
|
108
|
+
type: 'options',
|
|
109
|
+
noDataExpression: true,
|
|
110
|
+
displayOptions: {
|
|
111
|
+
show: {
|
|
112
|
+
resource: ['lead'],
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
options: [
|
|
116
|
+
{
|
|
117
|
+
name: 'List',
|
|
118
|
+
value: 'list',
|
|
119
|
+
description: 'Listar todos los leads',
|
|
120
|
+
action: 'Listar leads',
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: 'Create',
|
|
124
|
+
value: 'create',
|
|
125
|
+
description: 'Crear un nuevo lead',
|
|
126
|
+
action: 'Crear lead',
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
default: 'list',
|
|
130
|
+
},
|
|
131
|
+
// Lead Create Fields
|
|
132
|
+
{
|
|
133
|
+
displayName: 'Nombre',
|
|
134
|
+
name: 'nombre',
|
|
135
|
+
type: 'string',
|
|
136
|
+
required: true,
|
|
137
|
+
displayOptions: {
|
|
138
|
+
show: {
|
|
139
|
+
resource: ['lead'],
|
|
140
|
+
operation: ['create'],
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
default: '',
|
|
144
|
+
description: 'Nombre completo del lead',
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
displayName: 'Teléfono',
|
|
148
|
+
name: 'telefono',
|
|
149
|
+
type: 'string',
|
|
150
|
+
required: true,
|
|
151
|
+
displayOptions: {
|
|
152
|
+
show: {
|
|
153
|
+
resource: ['lead'],
|
|
154
|
+
operation: ['create'],
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
default: '',
|
|
158
|
+
description: 'Número de teléfono del lead',
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
displayName: 'Mensaje',
|
|
162
|
+
name: 'mensaje',
|
|
163
|
+
type: 'string',
|
|
164
|
+
typeOptions: {
|
|
165
|
+
rows: 4,
|
|
166
|
+
},
|
|
167
|
+
required: true,
|
|
168
|
+
displayOptions: {
|
|
169
|
+
show: {
|
|
170
|
+
resource: ['lead'],
|
|
171
|
+
operation: ['create'],
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
default: '',
|
|
175
|
+
description: 'Mensaje o consulta del lead',
|
|
176
|
+
},
|
|
177
|
+
// ============================================
|
|
178
|
+
// TENANT OPERATIONS
|
|
179
|
+
// ============================================
|
|
180
|
+
{
|
|
181
|
+
displayName: 'Operación',
|
|
182
|
+
name: 'operation',
|
|
183
|
+
type: 'options',
|
|
184
|
+
noDataExpression: true,
|
|
185
|
+
displayOptions: {
|
|
186
|
+
show: {
|
|
187
|
+
resource: ['tenant'],
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
options: [
|
|
191
|
+
{
|
|
192
|
+
name: 'List',
|
|
193
|
+
value: 'list',
|
|
194
|
+
description: 'Listar todos los inquilinos',
|
|
195
|
+
action: 'Listar inquilinos',
|
|
196
|
+
},
|
|
197
|
+
],
|
|
198
|
+
default: 'list',
|
|
199
|
+
},
|
|
200
|
+
// ============================================
|
|
201
|
+
// MAINTENANCE ORDER OPERATIONS
|
|
202
|
+
// ============================================
|
|
203
|
+
{
|
|
204
|
+
displayName: 'Operación',
|
|
205
|
+
name: 'operation',
|
|
206
|
+
type: 'options',
|
|
207
|
+
noDataExpression: true,
|
|
208
|
+
displayOptions: {
|
|
209
|
+
show: {
|
|
210
|
+
resource: ['maintenanceOrder'],
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
options: [
|
|
214
|
+
{
|
|
215
|
+
name: 'Check Duplicate',
|
|
216
|
+
value: 'checkDuplicate',
|
|
217
|
+
description: 'Verificar si existe orden duplicada',
|
|
218
|
+
action: 'Verificar duplicado',
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
name: 'Create',
|
|
222
|
+
value: 'create',
|
|
223
|
+
description: 'Crear nueva orden de trabajo',
|
|
224
|
+
action: 'Crear orden',
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
name: 'Get',
|
|
228
|
+
value: 'get',
|
|
229
|
+
description: 'Obtener orden por ID',
|
|
230
|
+
action: 'Obtener orden',
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
name: 'Update',
|
|
234
|
+
value: 'update',
|
|
235
|
+
description: 'Actualizar orden existente',
|
|
236
|
+
action: 'Actualizar orden',
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
name: 'List',
|
|
240
|
+
value: 'list',
|
|
241
|
+
description: 'Listar órdenes de trabajo',
|
|
242
|
+
action: 'Listar órdenes',
|
|
243
|
+
},
|
|
244
|
+
],
|
|
245
|
+
default: 'list',
|
|
246
|
+
},
|
|
247
|
+
// Maintenance Order - Check Duplicate Fields
|
|
248
|
+
{
|
|
249
|
+
displayName: 'Property ID',
|
|
250
|
+
name: 'propiedadId',
|
|
251
|
+
type: 'number',
|
|
252
|
+
required: true,
|
|
253
|
+
displayOptions: {
|
|
254
|
+
show: {
|
|
255
|
+
resource: ['maintenanceOrder'],
|
|
256
|
+
operation: ['checkDuplicate'],
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
default: 0,
|
|
260
|
+
description: 'ID de la propiedad',
|
|
261
|
+
},
|
|
262
|
+
// Maintenance Order - Get/Update ID Field
|
|
263
|
+
{
|
|
264
|
+
displayName: 'Order ID',
|
|
265
|
+
name: 'orderId',
|
|
266
|
+
type: 'number',
|
|
267
|
+
required: true,
|
|
268
|
+
displayOptions: {
|
|
269
|
+
show: {
|
|
270
|
+
resource: ['maintenanceOrder'],
|
|
271
|
+
operation: ['get', 'update'],
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
default: 0,
|
|
275
|
+
description: 'ID de la orden de trabajo',
|
|
276
|
+
},
|
|
277
|
+
// Maintenance Order - Create Fields
|
|
278
|
+
{
|
|
279
|
+
displayName: 'Cliente ID',
|
|
280
|
+
name: 'clienteId',
|
|
281
|
+
type: 'number',
|
|
282
|
+
required: true,
|
|
283
|
+
displayOptions: {
|
|
284
|
+
show: {
|
|
285
|
+
resource: ['maintenanceOrder'],
|
|
286
|
+
operation: ['create'],
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
default: 0,
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
displayName: 'Propiedad ID',
|
|
293
|
+
name: 'propiedadId',
|
|
294
|
+
type: 'number',
|
|
295
|
+
required: true,
|
|
296
|
+
displayOptions: {
|
|
297
|
+
show: {
|
|
298
|
+
resource: ['maintenanceOrder'],
|
|
299
|
+
operation: ['create'],
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
default: 0,
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
displayName: 'Contratista ID',
|
|
306
|
+
name: 'contratistaId',
|
|
307
|
+
type: 'number',
|
|
308
|
+
required: true,
|
|
309
|
+
displayOptions: {
|
|
310
|
+
show: {
|
|
311
|
+
resource: ['maintenanceOrder'],
|
|
312
|
+
operation: ['create'],
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
default: 0,
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
displayName: 'Categoría',
|
|
319
|
+
name: 'categoria',
|
|
320
|
+
type: 'options',
|
|
321
|
+
required: true,
|
|
322
|
+
displayOptions: {
|
|
323
|
+
show: {
|
|
324
|
+
resource: ['maintenanceOrder'],
|
|
325
|
+
operation: ['create'],
|
|
326
|
+
},
|
|
327
|
+
},
|
|
328
|
+
options: [
|
|
329
|
+
{ name: 'Fontanería', value: 'fontanería' },
|
|
330
|
+
{ name: 'Electricidad', value: 'electricidad' },
|
|
331
|
+
{ name: 'Pintura', value: 'pintura' },
|
|
332
|
+
{ name: 'Cerrajería', value: 'cerrajería' },
|
|
333
|
+
{ name: 'Carpintería', value: 'carpintería' },
|
|
334
|
+
{ name: 'Aires Acondicionados', value: 'aires_acondicionados' },
|
|
335
|
+
{ name: 'Otro', value: 'otro' },
|
|
336
|
+
],
|
|
337
|
+
default: 'fontanería',
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
displayName: 'Urgencia',
|
|
341
|
+
name: 'urgencia',
|
|
342
|
+
type: 'options',
|
|
343
|
+
required: true,
|
|
344
|
+
displayOptions: {
|
|
345
|
+
show: {
|
|
346
|
+
resource: ['maintenanceOrder'],
|
|
347
|
+
operation: ['create'],
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
options: [
|
|
351
|
+
{ name: 'Baja', value: 'baja' },
|
|
352
|
+
{ name: 'Media', value: 'media' },
|
|
353
|
+
{ name: 'Alta', value: 'alta' },
|
|
354
|
+
],
|
|
355
|
+
default: 'media',
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
displayName: 'Descripción Corta',
|
|
359
|
+
name: 'descripcionCorta',
|
|
360
|
+
type: 'string',
|
|
361
|
+
required: true,
|
|
362
|
+
displayOptions: {
|
|
363
|
+
show: {
|
|
364
|
+
resource: ['maintenanceOrder'],
|
|
365
|
+
operation: ['create'],
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
default: '',
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
displayName: 'Descripción Detallada',
|
|
372
|
+
name: 'descripcionDetallada',
|
|
373
|
+
type: 'string',
|
|
374
|
+
typeOptions: { rows: 4 },
|
|
375
|
+
required: true,
|
|
376
|
+
displayOptions: {
|
|
377
|
+
show: {
|
|
378
|
+
resource: ['maintenanceOrder'],
|
|
379
|
+
operation: ['create'],
|
|
380
|
+
},
|
|
381
|
+
},
|
|
382
|
+
default: '',
|
|
383
|
+
},
|
|
384
|
+
// ============================================
|
|
385
|
+
// CONTRACTOR OPERATIONS
|
|
386
|
+
// ============================================
|
|
387
|
+
{
|
|
388
|
+
displayName: 'Operación',
|
|
389
|
+
name: 'operation',
|
|
390
|
+
type: 'options',
|
|
391
|
+
noDataExpression: true,
|
|
392
|
+
displayOptions: {
|
|
393
|
+
show: {
|
|
394
|
+
resource: ['contractor'],
|
|
395
|
+
},
|
|
396
|
+
},
|
|
397
|
+
options: [
|
|
398
|
+
{
|
|
399
|
+
name: 'Find By Category',
|
|
400
|
+
value: 'findByCategory',
|
|
401
|
+
description: 'Buscar contratista por categoría',
|
|
402
|
+
action: 'Buscar por categoría',
|
|
403
|
+
},
|
|
404
|
+
{
|
|
405
|
+
name: 'Find Alternatives',
|
|
406
|
+
value: 'findAlternatives',
|
|
407
|
+
description: 'Buscar contratistas alternativos',
|
|
408
|
+
action: 'Buscar alternativos',
|
|
409
|
+
},
|
|
410
|
+
],
|
|
411
|
+
default: 'findByCategory',
|
|
412
|
+
},
|
|
413
|
+
// Contractor - Find By Category
|
|
414
|
+
{
|
|
415
|
+
displayName: 'Categoría',
|
|
416
|
+
name: 'categoria',
|
|
417
|
+
type: 'options',
|
|
418
|
+
required: true,
|
|
419
|
+
displayOptions: {
|
|
420
|
+
show: {
|
|
421
|
+
resource: ['contractor'],
|
|
422
|
+
operation: ['findByCategory'],
|
|
423
|
+
},
|
|
424
|
+
},
|
|
425
|
+
options: [
|
|
426
|
+
{ name: 'Fontanería', value: 'fontanería' },
|
|
427
|
+
{ name: 'Electricidad', value: 'electricidad' },
|
|
428
|
+
{ name: 'Pintura', value: 'pintura' },
|
|
429
|
+
{ name: 'Cerrajería', value: 'cerrajería' },
|
|
430
|
+
{ name: 'Carpintería', value: 'carpintería' },
|
|
431
|
+
{ name: 'Aires Acondicionados', value: 'aires_acondicionados' },
|
|
432
|
+
],
|
|
433
|
+
default: 'fontanería',
|
|
434
|
+
},
|
|
435
|
+
// ============================================
|
|
436
|
+
// MONTHLY COST OPERATIONS
|
|
437
|
+
// ============================================
|
|
438
|
+
{
|
|
439
|
+
displayName: 'Operación',
|
|
440
|
+
name: 'operation',
|
|
441
|
+
type: 'options',
|
|
442
|
+
noDataExpression: true,
|
|
443
|
+
displayOptions: {
|
|
444
|
+
show: {
|
|
445
|
+
resource: ['monthlyCost'],
|
|
446
|
+
},
|
|
447
|
+
},
|
|
448
|
+
options: [
|
|
449
|
+
{
|
|
450
|
+
name: 'Track',
|
|
451
|
+
value: 'track',
|
|
452
|
+
description: 'Registrar costo mensual',
|
|
453
|
+
action: 'Registrar costo',
|
|
454
|
+
},
|
|
455
|
+
],
|
|
456
|
+
default: 'track',
|
|
457
|
+
},
|
|
458
|
+
// Monthly Cost - Track Fields
|
|
459
|
+
{
|
|
460
|
+
displayName: 'Mes',
|
|
461
|
+
name: 'mes',
|
|
462
|
+
type: 'number',
|
|
463
|
+
required: true,
|
|
464
|
+
displayOptions: {
|
|
465
|
+
show: {
|
|
466
|
+
resource: ['monthlyCost'],
|
|
467
|
+
operation: ['track'],
|
|
468
|
+
},
|
|
469
|
+
},
|
|
470
|
+
default: new Date().getMonth() + 1,
|
|
471
|
+
description: 'Mes (1-12)',
|
|
472
|
+
},
|
|
473
|
+
{
|
|
474
|
+
displayName: 'Año',
|
|
475
|
+
name: 'anio',
|
|
476
|
+
type: 'number',
|
|
477
|
+
required: true,
|
|
478
|
+
displayOptions: {
|
|
479
|
+
show: {
|
|
480
|
+
resource: ['monthlyCost'],
|
|
481
|
+
operation: ['track'],
|
|
482
|
+
},
|
|
483
|
+
},
|
|
484
|
+
default: new Date().getFullYear(),
|
|
485
|
+
},
|
|
486
|
+
{
|
|
487
|
+
displayName: 'Categoría',
|
|
488
|
+
name: 'categoria',
|
|
489
|
+
type: 'string',
|
|
490
|
+
required: true,
|
|
491
|
+
displayOptions: {
|
|
492
|
+
show: {
|
|
493
|
+
resource: ['monthlyCost'],
|
|
494
|
+
operation: ['track'],
|
|
495
|
+
},
|
|
496
|
+
},
|
|
497
|
+
default: '',
|
|
498
|
+
},
|
|
499
|
+
{
|
|
500
|
+
displayName: 'Total Gastado',
|
|
501
|
+
name: 'totalGastado',
|
|
502
|
+
type: 'number',
|
|
503
|
+
required: true,
|
|
504
|
+
displayOptions: {
|
|
505
|
+
show: {
|
|
506
|
+
resource: ['monthlyCost'],
|
|
507
|
+
operation: ['track'],
|
|
508
|
+
},
|
|
509
|
+
},
|
|
510
|
+
default: 0,
|
|
511
|
+
},
|
|
512
|
+
// ============================================
|
|
513
|
+
// WHATSAPP OPERATIONS
|
|
514
|
+
// ============================================
|
|
515
|
+
{
|
|
516
|
+
displayName: 'Operación',
|
|
517
|
+
name: 'operation',
|
|
518
|
+
type: 'options',
|
|
519
|
+
noDataExpression: true,
|
|
520
|
+
displayOptions: {
|
|
521
|
+
show: {
|
|
522
|
+
resource: ['whatsapp'],
|
|
523
|
+
},
|
|
524
|
+
},
|
|
525
|
+
options: [
|
|
526
|
+
{
|
|
527
|
+
name: 'Send Message',
|
|
528
|
+
value: 'sendMessage',
|
|
529
|
+
description: 'Enviar mensaje por WhatsApp',
|
|
530
|
+
action: 'Enviar mensaje',
|
|
531
|
+
},
|
|
532
|
+
],
|
|
533
|
+
default: 'sendMessage',
|
|
534
|
+
},
|
|
535
|
+
// WhatsApp - Send Message Fields
|
|
536
|
+
{
|
|
537
|
+
displayName: 'Número',
|
|
538
|
+
name: 'numero',
|
|
539
|
+
type: 'string',
|
|
540
|
+
required: true,
|
|
541
|
+
displayOptions: {
|
|
542
|
+
show: {
|
|
543
|
+
resource: ['whatsapp'],
|
|
544
|
+
operation: ['sendMessage'],
|
|
545
|
+
},
|
|
546
|
+
},
|
|
547
|
+
default: '',
|
|
548
|
+
placeholder: '5491112345678',
|
|
549
|
+
description: 'Número de WhatsApp (con código de país)',
|
|
550
|
+
},
|
|
551
|
+
{
|
|
552
|
+
displayName: 'Mensaje',
|
|
553
|
+
name: 'mensaje',
|
|
554
|
+
type: 'string',
|
|
555
|
+
typeOptions: { rows: 4 },
|
|
556
|
+
required: true,
|
|
557
|
+
displayOptions: {
|
|
558
|
+
show: {
|
|
559
|
+
resource: ['whatsapp'],
|
|
560
|
+
operation: ['sendMessage'],
|
|
561
|
+
},
|
|
562
|
+
},
|
|
563
|
+
default: '',
|
|
564
|
+
},
|
|
565
|
+
],
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
async execute() {
|
|
569
|
+
const items = this.getInputData();
|
|
570
|
+
const returnData = [];
|
|
571
|
+
const credentials = await this.getCredentials('aivenceRealtyApi');
|
|
572
|
+
const baseUrl = credentials.baseUrl;
|
|
573
|
+
for (let i = 0; i < items.length; i++) {
|
|
574
|
+
try {
|
|
575
|
+
const resource = this.getNodeParameter('resource', i);
|
|
576
|
+
const operation = this.getNodeParameter('operation', i);
|
|
577
|
+
let responseData;
|
|
578
|
+
// ============================================
|
|
579
|
+
// PROPERTY RESOURCE
|
|
580
|
+
// ============================================
|
|
581
|
+
if (resource === 'property') {
|
|
582
|
+
if (operation === 'list') {
|
|
583
|
+
responseData = await this.helpers.httpRequest({
|
|
584
|
+
method: 'GET',
|
|
585
|
+
url: `${baseUrl}/api/v1/properties`,
|
|
586
|
+
json: true,
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
else if (operation === 'getSimilar') {
|
|
590
|
+
responseData = await this.helpers.httpRequest({
|
|
591
|
+
method: 'GET',
|
|
592
|
+
url: `${baseUrl}/api/v1/properties/similares`,
|
|
593
|
+
json: true,
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
else if (operation === 'getStatistics') {
|
|
597
|
+
responseData = await this.helpers.httpRequest({
|
|
598
|
+
method: 'GET',
|
|
599
|
+
url: `${baseUrl}/api/v1/properties/estadisticas`,
|
|
600
|
+
json: true,
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
// ============================================
|
|
605
|
+
// LEAD RESOURCE
|
|
606
|
+
// ============================================
|
|
607
|
+
else if (resource === 'lead') {
|
|
608
|
+
if (operation === 'list') {
|
|
609
|
+
responseData = await this.helpers.httpRequest({
|
|
610
|
+
method: 'GET',
|
|
611
|
+
url: `${baseUrl}/api/v1/leads`,
|
|
612
|
+
json: true,
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
else if (operation === 'create') {
|
|
616
|
+
const body = {
|
|
617
|
+
nombre: this.getNodeParameter('nombre', i),
|
|
618
|
+
telefono: this.getNodeParameter('telefono', i),
|
|
619
|
+
mensaje: this.getNodeParameter('mensaje', i),
|
|
620
|
+
};
|
|
621
|
+
responseData = await this.helpers.httpRequest({
|
|
622
|
+
method: 'POST',
|
|
623
|
+
url: `${baseUrl}/api/v1/leads`,
|
|
624
|
+
body,
|
|
625
|
+
json: true,
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
// ============================================
|
|
630
|
+
// TENANT RESOURCE
|
|
631
|
+
// ============================================
|
|
632
|
+
else if (resource === 'tenant') {
|
|
633
|
+
if (operation === 'list') {
|
|
634
|
+
responseData = await this.helpers.httpRequest({
|
|
635
|
+
method: 'GET',
|
|
636
|
+
url: `${baseUrl}/api/v1/tenants`,
|
|
637
|
+
json: true,
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
// ============================================
|
|
642
|
+
// MAINTENANCE ORDER RESOURCE
|
|
643
|
+
// ============================================
|
|
644
|
+
else if (resource === 'maintenanceOrder') {
|
|
645
|
+
if (operation === 'checkDuplicate') {
|
|
646
|
+
const body = {
|
|
647
|
+
propiedad_id: this.getNodeParameter('propiedadId', i),
|
|
648
|
+
estado: 'abierto',
|
|
649
|
+
};
|
|
650
|
+
responseData = await this.helpers.httpRequest({
|
|
651
|
+
method: 'POST',
|
|
652
|
+
url: `${baseUrl}/api/ordenes-trabajo/verificar-duplicado`,
|
|
653
|
+
body,
|
|
654
|
+
json: true,
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
else if (operation === 'create') {
|
|
658
|
+
const body = {
|
|
659
|
+
cliente_id: this.getNodeParameter('clienteId', i),
|
|
660
|
+
propiedad_id: this.getNodeParameter('propiedadId', i),
|
|
661
|
+
contratista_id: this.getNodeParameter('contratistaId', i),
|
|
662
|
+
categoria: this.getNodeParameter('categoria', i),
|
|
663
|
+
urgencia: this.getNodeParameter('urgencia', i),
|
|
664
|
+
descripcion_corta: this.getNodeParameter('descripcionCorta', i),
|
|
665
|
+
descripcion_detallada: this.getNodeParameter('descripcionDetallada', i),
|
|
666
|
+
estado: 'pendiente_aceptacion',
|
|
667
|
+
};
|
|
668
|
+
responseData = await this.helpers.httpRequest({
|
|
669
|
+
method: 'POST',
|
|
670
|
+
url: `${baseUrl}/api/ordenes-trabajo`,
|
|
671
|
+
body,
|
|
672
|
+
json: true,
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
else if (operation === 'get') {
|
|
676
|
+
const orderId = this.getNodeParameter('orderId', i);
|
|
677
|
+
responseData = await this.helpers.httpRequest({
|
|
678
|
+
method: 'GET',
|
|
679
|
+
url: `${baseUrl}/api/ordenes-trabajo/${orderId}`,
|
|
680
|
+
json: true,
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
else if (operation === 'update') {
|
|
684
|
+
const orderId = this.getNodeParameter('orderId', i);
|
|
685
|
+
// Aquí puedes añadir los campos a actualizar según necesites
|
|
686
|
+
responseData = await this.helpers.httpRequest({
|
|
687
|
+
method: 'PATCH',
|
|
688
|
+
url: `${baseUrl}/api/ordenes-trabajo/${orderId}`,
|
|
689
|
+
body: {},
|
|
690
|
+
json: true,
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
else if (operation === 'list') {
|
|
694
|
+
responseData = await this.helpers.httpRequest({
|
|
695
|
+
method: 'GET',
|
|
696
|
+
url: `${baseUrl}/api/ordenes-trabajo`,
|
|
697
|
+
json: true,
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
// ============================================
|
|
702
|
+
// CONTRACTOR RESOURCE
|
|
703
|
+
// ============================================
|
|
704
|
+
else if (resource === 'contractor') {
|
|
705
|
+
if (operation === 'findByCategory') {
|
|
706
|
+
const categoria = this.getNodeParameter('categoria', i);
|
|
707
|
+
responseData = await this.helpers.httpRequest({
|
|
708
|
+
method: 'GET',
|
|
709
|
+
url: `${baseUrl}/api/contratistas/por-categoria`,
|
|
710
|
+
qs: { categoria },
|
|
711
|
+
json: true,
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
else if (operation === 'findAlternatives') {
|
|
715
|
+
responseData = await this.helpers.httpRequest({
|
|
716
|
+
method: 'GET',
|
|
717
|
+
url: `${baseUrl}/api/contratistas/alternativos`,
|
|
718
|
+
json: true,
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
// ============================================
|
|
723
|
+
// MONTHLY COST RESOURCE
|
|
724
|
+
// ============================================
|
|
725
|
+
else if (resource === 'monthlyCost') {
|
|
726
|
+
if (operation === 'track') {
|
|
727
|
+
const body = {
|
|
728
|
+
mes: this.getNodeParameter('mes', i),
|
|
729
|
+
anio: this.getNodeParameter('anio', i),
|
|
730
|
+
categoria: this.getNodeParameter('categoria', i),
|
|
731
|
+
total_gastado: this.getNodeParameter('totalGastado', i),
|
|
732
|
+
};
|
|
733
|
+
responseData = await this.helpers.httpRequest({
|
|
734
|
+
method: 'POST',
|
|
735
|
+
url: `${baseUrl}/api/costos-mensuales`,
|
|
736
|
+
body,
|
|
737
|
+
json: true,
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
// ============================================
|
|
742
|
+
// WHATSAPP RESOURCE
|
|
743
|
+
// ============================================
|
|
744
|
+
else if (resource === 'whatsapp') {
|
|
745
|
+
if (operation === 'sendMessage') {
|
|
746
|
+
const body = {
|
|
747
|
+
number: this.getNodeParameter('numero', i),
|
|
748
|
+
text: this.getNodeParameter('mensaje', i),
|
|
749
|
+
};
|
|
750
|
+
responseData = await this.helpers.httpRequest({
|
|
751
|
+
method: 'POST',
|
|
752
|
+
url: `${baseUrl}/api/evolution/send-message`,
|
|
753
|
+
body,
|
|
754
|
+
json: true,
|
|
755
|
+
});
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
// Formatear respuesta
|
|
759
|
+
const executionData = this.helpers.constructExecutionMetaData(this.helpers.returnJsonArray(responseData), { itemData: { item: i } });
|
|
760
|
+
returnData.push(...executionData);
|
|
761
|
+
}
|
|
762
|
+
catch (error) {
|
|
763
|
+
if (this.continueOnFail()) {
|
|
764
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
765
|
+
returnData.push({
|
|
766
|
+
json: { error: errorMessage },
|
|
767
|
+
pairedItem: { item: i },
|
|
768
|
+
});
|
|
769
|
+
continue;
|
|
770
|
+
}
|
|
771
|
+
throw error;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
return [returnData];
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
exports.AivenceRealty = AivenceRealty;
|
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "n8n-nodes-aivence-realty",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Nodo n8n para integrar el CRM inmobiliario AivenceRealty",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"n8n-community-node-package",
|
|
7
|
+
"n8n-nodes",
|
|
8
|
+
"AivenceRealty",
|
|
9
|
+
"CRM",
|
|
10
|
+
"Real Estate",
|
|
11
|
+
"Inmobiliario",
|
|
12
|
+
"Laravel"
|
|
13
|
+
],
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"homepage": "https://realty.aivence.com",
|
|
16
|
+
"author": {
|
|
17
|
+
"name": "Federico Aivence",
|
|
18
|
+
"email": "federico@aivence.com"
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "https://github.com/aivence/n8n-nodes-aivence-realty.git"
|
|
23
|
+
},
|
|
24
|
+
"main": "index.js",
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc && gulp build:icons",
|
|
27
|
+
"dev": "tsc --watch",
|
|
28
|
+
"format": "prettier nodes credentials --write",
|
|
29
|
+
"lint": "eslint nodes credentials package.json",
|
|
30
|
+
"lintfix": "eslint nodes credentials package.json --fix",
|
|
31
|
+
"prepublishOnly": "npm run build"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist"
|
|
35
|
+
],
|
|
36
|
+
"n8n": {
|
|
37
|
+
"n8nNodesApiVersion": 1,
|
|
38
|
+
"credentials": [
|
|
39
|
+
"dist/credentials/AivenceRealtyApi.credentials.js"
|
|
40
|
+
],
|
|
41
|
+
"nodes": [
|
|
42
|
+
"dist/nodes/AivenceRealty/AivenceRealty.node.js"
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@typescript-eslint/parser": "^7.15.0",
|
|
47
|
+
"eslint": "^8.56.0",
|
|
48
|
+
"eslint-plugin-n8n-nodes-base": "^1.16.1",
|
|
49
|
+
"gulp": "^4.0.2",
|
|
50
|
+
"n8n-workflow": "^1.0.0",
|
|
51
|
+
"prettier": "^3.3.2",
|
|
52
|
+
"typescript": "^5.5.3"
|
|
53
|
+
},
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"n8n-workflow": "*"
|
|
56
|
+
}
|
|
57
|
+
}
|