n8n-nodes-ifood-completo 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/CHANGELOG.md ADDED
@@ -0,0 +1,8 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0
4
+
5
+ - Versão inicial do pacote `n8n-nodes-ifood-completo`.
6
+ - Inclui credencial `iFood Completo API`.
7
+ - Inclui node `iFood Completo` com operações para Authentication, Merchant, Events, Order, Financial, Catalog, Logistics, Shipping e Review.
8
+ - Inclui operações customizadas por módulo para endpoints adicionais da Merchant API do iFood.
package/PUBLISHING.md ADDED
@@ -0,0 +1,49 @@
1
+ # Publicação no npm
2
+
3
+ ## Pré-requisitos
4
+
5
+ - Conta no npm com permissão para publicar o pacote `n8n-nodes-ifood-completo`.
6
+ - Node.js e npm instalados no ambiente de publicação.
7
+ - Acesso ao diretório `lib/vendor/ifood_completo/n8n`.
8
+
9
+ ## Validar localmente
10
+
11
+ ```bash
12
+ cd lib/vendor/ifood_completo/n8n
13
+ npm run validate
14
+ npm run publish:dry-run
15
+ ```
16
+
17
+ ## Gerar pacote local
18
+
19
+ ```bash
20
+ npm run release:pack
21
+ ```
22
+
23
+ Isso cria um arquivo `.tgz` que pode ser instalado manualmente no n8n para teste.
24
+
25
+ ## Publicar no npm
26
+
27
+ ```bash
28
+ npm login
29
+ npm publish --access public
30
+ ```
31
+
32
+ Se o pacote for privado ou restrito a uma organização, ajuste `publishConfig.access` no `package.json` antes da publicação.
33
+
34
+ ## Atualizar versão
35
+
36
+ Antes de publicar uma nova versão:
37
+
38
+ ```bash
39
+ npm version patch
40
+ npm publish --access public
41
+ ```
42
+
43
+ Use `minor` ou `major` quando houver mudança funcional relevante ou quebra de compatibilidade.
44
+
45
+ ## Observações
46
+
47
+ - Não publique tokens, credenciais, arquivos `.env` ou pacotes `.tgz` gerados localmente.
48
+ - A keyword `n8n-community-node-package` deve permanecer no `package.json` para o n8n reconhecer o pacote como community node.
49
+ - O nome do pacote deve continuar iniciando com `n8n-nodes-`.
package/README.md ADDED
@@ -0,0 +1,111 @@
1
+ # n8n-nodes-ifood-completo
2
+
3
+ Pacote npm local com node customizado para usar a Merchant API do iFood no n8n.
4
+
5
+ ## Módulos disponíveis
6
+
7
+ O node `iFood Completo` concentra operações para os módulos criados em `lib/vendor/ifood_completo`:
8
+
9
+ - `Authentication`: gerar token `client_credentials`, refresh token e user code.
10
+ - `Merchant`: listar lojas, consultar detalhes/status, horários, interrupções e QR code de check-in.
11
+ - `Events`: polling e acknowledgment de eventos.
12
+ - `Order`: detalhes do pedido, confirmação, preparo, retirada, despacho, cancelamento, motivos e rastreio.
13
+ - `Financial`: Sales, Reconciliation, Settlements, Financial Events, Reconciliation On Demand e Anticipations.
14
+ - `Catalog`: catálogos, categorias, itens e endpoint customizado.
15
+ - `Logistics`: consulta logística por pedido e endpoint customizado.
16
+ - `Shipping`: cotação, criação, consulta e cancelamento de entregas.
17
+ - `Review`: listagem, detalhe, resposta e endpoint customizado.
18
+
19
+ ## Instalação local para desenvolvimento
20
+
21
+ Dentro deste diretório:
22
+
23
+ ```bash
24
+ cd lib/vendor/ifood_completo/n8n
25
+ npm install
26
+ npm run dev
27
+ ```
28
+
29
+ O comando `npm run dev` usa o `@n8n/node-cli` para carregar o pacote em um n8n local de desenvolvimento.
30
+
31
+ ## Gerar pacote `.tgz`
32
+
33
+ ```bash
34
+ cd lib/vendor/ifood_completo/n8n
35
+ npm pack
36
+ ```
37
+
38
+ Depois instale o arquivo gerado no ambiente do n8n:
39
+
40
+ ```bash
41
+ npm install /caminho/n8n-nodes-ifood-completo-0.1.0.tgz
42
+ ```
43
+
44
+ Em Docker, monte ou copie o pacote para o container e instale no diretório onde o n8n carrega community nodes.
45
+
46
+ ## Credenciais
47
+
48
+ Crie uma credencial do tipo `iFood Completo API` com:
49
+
50
+ - `Access Token`: token Bearer retornado pelo endpoint OAuth do iFood.
51
+ - `Base URL`: por padrão `https://merchant-api.ifood.com.br`.
52
+
53
+ As operações do módulo `Authentication` não exigem credencial. Informe `clientId`, `clientSecret` ou demais dados no campo `Body JSON`.
54
+
55
+ Exemplo para `Authentication: Client Credentials`:
56
+
57
+ ```json
58
+ {
59
+ "clientId": "SEU_CLIENT_ID",
60
+ "clientSecret": "SEU_CLIENT_SECRET"
61
+ }
62
+ ```
63
+
64
+ ## Campos gerais do node
65
+
66
+ - `Módulo`: organiza visualmente a operação selecionada.
67
+ - `Operação`: ação executada.
68
+ - `Merchant ID`: ID da loja iFood.
69
+ - `Order ID / ID`: ID principal usado pela operação, como pedido, review, entrega, interrupção ou request.
70
+ - `Data Inicial` e `Data Final`: períodos financeiros ou consultas por data.
71
+ - `Competência`: competência mensal no formato `YYYY-MM`.
72
+ - `Query JSON`: query string adicional.
73
+ - `Body JSON`: payload da requisição.
74
+ - `Método Customizado` e `Path Customizado`: usados nas operações de endpoint customizado.
75
+
76
+ ## Exemplos
77
+
78
+ Consultar vendas financeiras:
79
+
80
+ - Módulo: `Financial`
81
+ - Operação: `Financial: Sales`
82
+ - Merchant ID: `merchantId`
83
+ - Data Inicial: `2026-08-01`
84
+ - Data Final: `2026-08-31`
85
+ - Query JSON: `{"page":1,"size":100}`
86
+
87
+ Consultar arquivo de conciliação:
88
+
89
+ - Módulo: `Financial`
90
+ - Operação: `Financial: Reconciliation Arquivo`
91
+ - Merchant ID: `merchantId`
92
+ - Competência: `2026-08`
93
+
94
+ Polling de eventos:
95
+
96
+ - Módulo: `Events`
97
+ - Operação: `Events: Polling`
98
+
99
+ Confirmar pedido:
100
+
101
+ - Módulo: `Order`
102
+ - Operação: `Order: Confirmar`
103
+ - Order ID / ID: `orderId`
104
+ - Body JSON: `{}`
105
+
106
+ ## Observações
107
+
108
+ - Este pacote não altera nenhum script PHP existente.
109
+ - O pacote usa JavaScript CommonJS direto, sem etapa obrigatória de build.
110
+ - Alguns endpoints podem depender de permissão liberada no app iFood e podem retornar `403` se o app não possuir escopo.
111
+ - Use operações customizadas quando a documentação do iFood adicionar parâmetros ou paths novos dentro do mesmo módulo.
@@ -0,0 +1,34 @@
1
+ class IfoodCompletoApi {
2
+ constructor() {
3
+ this.name = 'ifoodCompletoApi';
4
+ this.displayName = 'iFood Completo API';
5
+ this.documentationUrl = 'https://developer.ifood.com.br/';
6
+ this.authenticate = {
7
+ type: 'generic',
8
+ properties: {
9
+ headers: {
10
+ Authorization: '=Bearer {{$credentials.accessToken}}',
11
+ },
12
+ },
13
+ };
14
+ this.properties = [
15
+ {
16
+ displayName: 'Access Token',
17
+ name: 'accessToken',
18
+ type: 'string',
19
+ typeOptions: { password: true },
20
+ default: '',
21
+ description: 'Token Bearer gerado pela API de autenticação do iFood.',
22
+ },
23
+ {
24
+ displayName: 'Base URL',
25
+ name: 'baseUrl',
26
+ type: 'string',
27
+ default: 'https://merchant-api.ifood.com.br',
28
+ description: 'URL base da Merchant API do iFood.',
29
+ },
30
+ ];
31
+ }
32
+ }
33
+
34
+ exports.IfoodCompletoApi = IfoodCompletoApi;
package/helpers/api.js ADDED
@@ -0,0 +1,52 @@
1
+ async function ifoodApiRequest(method, path, body, qs, authentication) {
2
+ const credentials = authentication === false ? { baseUrl: 'https://merchant-api.ifood.com.br' } : await this.getCredentials('ifoodCompletoApi');
3
+ const baseUrl = String(credentials.baseUrl || 'https://merchant-api.ifood.com.br').replace(/\/$/, '');
4
+ const options = {
5
+ method,
6
+ url: /^https?:\/\//i.test(path) ? path : `${baseUrl}/${String(path).replace(/^\//, '')}`,
7
+ json: true,
8
+ qs: qs || {},
9
+ headers: {
10
+ Accept: 'application/json',
11
+ },
12
+ };
13
+
14
+ if (body !== undefined && body !== null && method !== 'GET') {
15
+ options.body = body;
16
+ }
17
+
18
+ if (authentication === false) {
19
+ if (body && typeof body === 'object') {
20
+ options.form = body;
21
+ delete options.body;
22
+ }
23
+ options.headers['Content-Type'] = 'application/x-www-form-urlencoded';
24
+ return this.helpers.httpRequest(options);
25
+ }
26
+
27
+ return this.helpers.httpRequestWithAuthentication.call(this, 'ifoodCompletoApi', options);
28
+ }
29
+
30
+ function parseJson(value, fallback) {
31
+ if (value === undefined || value === null || value === '') return fallback;
32
+ if (typeof value === 'object') return value;
33
+ try {
34
+ return JSON.parse(value);
35
+ } catch (error) {
36
+ throw new Error(`JSON inválido: ${error.message}`);
37
+ }
38
+ }
39
+
40
+ function compactQuery(query) {
41
+ const clean = {};
42
+ Object.keys(query || {}).forEach((key) => {
43
+ if (query[key] !== undefined && query[key] !== null && query[key] !== '') clean[key] = query[key];
44
+ });
45
+ return clean;
46
+ }
47
+
48
+ module.exports = {
49
+ ifoodApiRequest,
50
+ parseJson,
51
+ compactQuery,
52
+ };
package/index.js ADDED
@@ -0,0 +1 @@
1
+ module.exports = {};
@@ -0,0 +1,227 @@
1
+ const { ifoodApiRequest, parseJson, compactQuery } = require('../../helpers/api');
2
+
3
+ class IfoodCompleto {
4
+ constructor() {
5
+ this.description = {
6
+ displayName: 'iFood Completo',
7
+ name: 'ifoodCompleto',
8
+ icon: 'fa:store',
9
+ group: ['transform'],
10
+ version: 1,
11
+ subtitle: '={{$parameter["resource"] + ": " + $parameter["operation"]}}',
12
+ description: 'Merchant API iFood: autenticação, lojas, eventos, pedidos, financeiro, catálogo, logística, shipping e avaliações.',
13
+ defaults: {
14
+ name: 'iFood Completo',
15
+ },
16
+ inputs: ['main'],
17
+ outputs: ['main'],
18
+ credentials: [
19
+ {
20
+ name: 'ifoodCompletoApi',
21
+ required: false,
22
+ displayOptions: {
23
+ hide: {
24
+ resource: ['authentication'],
25
+ },
26
+ },
27
+ },
28
+ ],
29
+ properties: [
30
+ {
31
+ displayName: 'Módulo',
32
+ name: 'resource',
33
+ type: 'options',
34
+ default: 'financial',
35
+ options: [
36
+ { name: 'Authentication', value: 'authentication' },
37
+ { name: 'Catalog', value: 'catalog' },
38
+ { name: 'Events', value: 'events' },
39
+ { name: 'Financial', value: 'financial' },
40
+ { name: 'Logistics', value: 'logistics' },
41
+ { name: 'Merchant', value: 'merchant' },
42
+ { name: 'Order', value: 'order' },
43
+ { name: 'Review', value: 'review' },
44
+ { name: 'Shipping', value: 'shipping' },
45
+ ],
46
+ },
47
+ {
48
+ displayName: 'Operação',
49
+ name: 'operation',
50
+ type: 'options',
51
+ default: 'sales',
52
+ options: [
53
+ { name: 'Authentication: Client Credentials', value: 'authClientCredentials' },
54
+ { name: 'Authentication: Refresh Token', value: 'authRefreshToken' },
55
+ { name: 'Authentication: User Code', value: 'authUserCode' },
56
+ { name: 'Catalog: Endpoint Customizado', value: 'catalogCustom' },
57
+ { name: 'Catalog: Listar Catálogos', value: 'catalogList' },
58
+ { name: 'Catalog: Listar Categorias', value: 'catalogCategories' },
59
+ { name: 'Catalog: Listar Itens', value: 'catalogItems' },
60
+ { name: 'Events: Acknowledgment', value: 'eventsAck' },
61
+ { name: 'Events: Endpoint Customizado', value: 'eventsCustom' },
62
+ { name: 'Events: Polling', value: 'eventsPolling' },
63
+ { name: 'Financial: Antecipações', value: 'financialAnticipations' },
64
+ { name: 'Financial: Conciliação On Demand - Criar', value: 'financialReconciliationOnDemandCreate' },
65
+ { name: 'Financial: Conciliação On Demand - Status', value: 'financialReconciliationOnDemandStatus' },
66
+ { name: 'Financial: Endpoint Customizado', value: 'financialCustom' },
67
+ { name: 'Financial: Eventos Financeiros', value: 'financialEvents' },
68
+ { name: 'Financial: Reconciliation Arquivo', value: 'financialReconciliation' },
69
+ { name: 'Financial: Sales', value: 'sales' },
70
+ { name: 'Financial: Settlements', value: 'settlements' },
71
+ { name: 'Logistics: Endpoint Customizado', value: 'logisticsCustom' },
72
+ { name: 'Logistics: Pedido', value: 'logisticsOrder' },
73
+ { name: 'Merchant: Criar Interrupção', value: 'merchantCreateInterruption' },
74
+ { name: 'Merchant: Deletar Interrupção', value: 'merchantDeleteInterruption' },
75
+ { name: 'Merchant: Detalhes', value: 'merchantDetails' },
76
+ { name: 'Merchant: Endpoint Customizado', value: 'merchantCustom' },
77
+ { name: 'Merchant: Horários', value: 'merchantOpeningHours' },
78
+ { name: 'Merchant: Interrupções', value: 'merchantInterruptions' },
79
+ { name: 'Merchant: Listar', value: 'merchantList' },
80
+ { name: 'Merchant: QR Code Check-in', value: 'merchantCheckinQrCode' },
81
+ { name: 'Merchant: Status', value: 'merchantStatus' },
82
+ { name: 'Merchant: Atualizar Horários', value: 'merchantUpdateOpeningHours' },
83
+ { name: 'Order: Cancellation Reasons', value: 'orderCancellationReasons' },
84
+ { name: 'Order: Confirmar', value: 'orderConfirm' },
85
+ { name: 'Order: Despachar', value: 'orderDispatch' },
86
+ { name: 'Order: Detalhes', value: 'orderDetails' },
87
+ { name: 'Order: Endpoint Customizado', value: 'orderCustom' },
88
+ { name: 'Order: Iniciar Preparo', value: 'orderStartPreparation' },
89
+ { name: 'Order: Pronto Para Retirada', value: 'orderReadyToPickup' },
90
+ { name: 'Order: Rastreio', value: 'orderTracking' },
91
+ { name: 'Order: Solicitar Cancelamento', value: 'orderRequestCancellation' },
92
+ { name: 'Review: Detalhes', value: 'reviewGet' },
93
+ { name: 'Review: Endpoint Customizado', value: 'reviewCustom' },
94
+ { name: 'Review: Listar', value: 'reviewList' },
95
+ { name: 'Review: Responder', value: 'reviewReply' },
96
+ { name: 'Shipping: Cancelar Entrega', value: 'shippingCancel' },
97
+ { name: 'Shipping: Consultar Entrega', value: 'shippingGet' },
98
+ { name: 'Shipping: Cotação', value: 'shippingQuote' },
99
+ { name: 'Shipping: Criar Entrega', value: 'shippingCreate' },
100
+ { name: 'Shipping: Endpoint Customizado', value: 'shippingCustom' },
101
+ ],
102
+ },
103
+ { displayName: 'Merchant ID', name: 'merchantId', type: 'string', default: '', description: 'ID da loja iFood.' },
104
+ { displayName: 'Order ID / ID', name: 'id', type: 'string', default: '', description: 'ID do pedido, entrega, review, request ou interrupção conforme a operação.' },
105
+ { displayName: 'ID Secundário', name: 'secondaryId', type: 'string', default: '', description: 'ID auxiliar, como catalogId, categoryId, interruptionId ou reviewId.' },
106
+ { displayName: 'Data Inicial', name: 'beginDate', type: 'string', default: '', placeholder: '2026-08-01' },
107
+ { displayName: 'Data Final', name: 'endDate', type: 'string', default: '', placeholder: '2026-08-31' },
108
+ { displayName: 'Competência', name: 'competence', type: 'string', default: '', placeholder: '2026-08' },
109
+ { displayName: 'Método Customizado', name: 'customMethod', type: 'options', default: 'GET', options: [{ name: 'GET', value: 'GET' }, { name: 'POST', value: 'POST' }, { name: 'PUT', value: 'PUT' }, { name: 'PATCH', value: 'PATCH' }, { name: 'DELETE', value: 'DELETE' }] },
110
+ { displayName: 'Path Customizado', name: 'customPath', type: 'string', default: '', placeholder: '/merchants ou /orders/{id}' },
111
+ { displayName: 'Query JSON', name: 'queryJson', type: 'json', default: '{}', description: 'Parâmetros query string em JSON.' },
112
+ { displayName: 'Body JSON', name: 'bodyJson', type: 'json', default: '{}', description: 'Payload JSON ou formulário para autenticação.' },
113
+ ],
114
+ };
115
+ }
116
+
117
+ async execute() {
118
+ const items = this.getInputData();
119
+ const returnData = [];
120
+
121
+ for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
122
+ const operation = this.getNodeParameter('operation', itemIndex);
123
+ const merchantId = this.getNodeParameter('merchantId', itemIndex, '');
124
+ const id = this.getNodeParameter('id', itemIndex, '');
125
+ const secondaryId = this.getNodeParameter('secondaryId', itemIndex, '');
126
+ const beginDate = this.getNodeParameter('beginDate', itemIndex, '');
127
+ const endDate = this.getNodeParameter('endDate', itemIndex, '');
128
+ const competence = this.getNodeParameter('competence', itemIndex, '');
129
+ const customMethod = this.getNodeParameter('customMethod', itemIndex, 'GET');
130
+ const customPath = this.getNodeParameter('customPath', itemIndex, '');
131
+ const queryJson = parseJson(this.getNodeParameter('queryJson', itemIndex, '{}'), {});
132
+ const bodyJson = parseJson(this.getNodeParameter('bodyJson', itemIndex, '{}'), {});
133
+
134
+ const response = await this.callOperation(operation, {
135
+ merchantId,
136
+ id,
137
+ secondaryId,
138
+ beginDate,
139
+ endDate,
140
+ competence,
141
+ customMethod,
142
+ customPath,
143
+ queryJson,
144
+ bodyJson,
145
+ });
146
+
147
+ returnData.push({ json: response });
148
+ }
149
+
150
+ return [returnData];
151
+ }
152
+
153
+ async callOperation(operation, p) {
154
+ const q = compactQuery(p.queryJson);
155
+ const body = p.bodyJson;
156
+ const replace = (path) => path
157
+ .replace('{merchantId}', encodeURIComponent(p.merchantId))
158
+ .replace('{id}', encodeURIComponent(p.id))
159
+ .replace('{secondaryId}', encodeURIComponent(p.secondaryId));
160
+
161
+ switch (operation) {
162
+ case 'authClientCredentials':
163
+ return ifoodApiRequest.call(this, 'POST', '/authentication/v1.0/oauth/token', Object.assign({ grantType: 'client_credentials' }, body), {}, false);
164
+ case 'authRefreshToken':
165
+ return ifoodApiRequest.call(this, 'POST', '/authentication/v1.0/oauth/token', Object.assign({ grantType: 'refresh_token' }, body), {}, false);
166
+ case 'authUserCode':
167
+ return ifoodApiRequest.call(this, 'POST', '/authentication/v1.0/oauth/userCode', body, {}, false);
168
+
169
+ case 'merchantList': return ifoodApiRequest.call(this, 'GET', '/merchant/v1.0/merchants', null, q);
170
+ case 'merchantDetails': return ifoodApiRequest.call(this, 'GET', replace('/merchant/v1.0/merchants/{merchantId}'), null, q);
171
+ case 'merchantStatus': return ifoodApiRequest.call(this, 'GET', replace('/merchant/v1.0/merchants/{merchantId}/status'), null, q);
172
+ case 'merchantInterruptions': return ifoodApiRequest.call(this, 'GET', replace('/merchant/v1.0/merchants/{merchantId}/interruptions'), null, q);
173
+ case 'merchantCreateInterruption': return ifoodApiRequest.call(this, 'POST', replace('/merchant/v1.0/merchants/{merchantId}/interruptions'), body, q);
174
+ case 'merchantDeleteInterruption': return ifoodApiRequest.call(this, 'DELETE', replace('/merchant/v1.0/merchants/{merchantId}/interruptions/{id}'), null, q);
175
+ case 'merchantOpeningHours': return ifoodApiRequest.call(this, 'GET', replace('/merchant/v1.0/merchants/{merchantId}/opening-hours'), null, q);
176
+ case 'merchantUpdateOpeningHours': return ifoodApiRequest.call(this, 'PUT', replace('/merchant/v1.0/merchants/{merchantId}/opening-hours'), body, q);
177
+ case 'merchantCheckinQrCode': return ifoodApiRequest.call(this, 'POST', '/merchant/v1.0/merchants/checkin-qrcode', body, q);
178
+ case 'merchantCustom': return ifoodApiRequest.call(this, p.customMethod, `/merchant/v1.0/${p.customPath.replace(/^\//, '')}`, body, q);
179
+
180
+ case 'eventsPolling': return ifoodApiRequest.call(this, 'GET', '/events/v1.0/events:polling', null, q);
181
+ case 'eventsAck': return ifoodApiRequest.call(this, 'POST', '/events/v1.0/events/acknowledgment', body, q);
182
+ case 'eventsCustom': return ifoodApiRequest.call(this, p.customMethod, `/events/v1.0/${p.customPath.replace(/^\//, '')}`, body, q);
183
+
184
+ case 'orderDetails': return ifoodApiRequest.call(this, 'GET', replace('/order/v1.0/orders/{id}'), null, q);
185
+ case 'orderConfirm': return ifoodApiRequest.call(this, 'POST', replace('/order/v1.0/orders/{id}/confirm'), body, q);
186
+ case 'orderStartPreparation': return ifoodApiRequest.call(this, 'POST', replace('/order/v1.0/orders/{id}/startPreparation'), body, q);
187
+ case 'orderReadyToPickup': return ifoodApiRequest.call(this, 'POST', replace('/order/v1.0/orders/{id}/readyToPickup'), body, q);
188
+ case 'orderDispatch': return ifoodApiRequest.call(this, 'POST', replace('/order/v1.0/orders/{id}/dispatch'), body, q);
189
+ case 'orderRequestCancellation': return ifoodApiRequest.call(this, 'POST', replace('/order/v1.0/orders/{id}/requestCancellation'), body, q);
190
+ case 'orderCancellationReasons': return ifoodApiRequest.call(this, 'GET', p.id ? replace('/order/v1.0/orders/{id}/cancellationReasons') : '/order/v1.0/cancellationReasons', null, q);
191
+ case 'orderTracking': return ifoodApiRequest.call(this, 'GET', replace('/order/v1.0/orders/{id}/tracking'), null, q);
192
+ case 'orderCustom': return ifoodApiRequest.call(this, p.customMethod, `/order/v1.0/${p.customPath.replace(/^\//, '')}`, body, q);
193
+
194
+ case 'sales': return ifoodApiRequest.call(this, 'GET', '/v3/sales', null, compactQuery(Object.assign({ merchantId: p.merchantId, beginSalesDate: p.beginDate, endSalesDate: p.endDate }, q)));
195
+ case 'financialReconciliation': return ifoodApiRequest.call(this, 'GET', replace('/financial/v3.0/merchants/{merchantId}/reconciliation'), null, compactQuery(Object.assign({ competence: p.competence }, q)));
196
+ case 'settlements': return ifoodApiRequest.call(this, 'GET', replace('/financial/v3.0/merchants/{merchantId}/settlements'), null, compactQuery(Object.assign({ beginPaymentDate: p.beginDate, endPaymentDate: p.endDate }, q)));
197
+ case 'financialEvents': return ifoodApiRequest.call(this, 'GET', '/v3/financial-events', null, compactQuery(Object.assign({ merchantId: p.merchantId, beginDate: p.beginDate, endDate: p.endDate }, q)));
198
+ case 'financialReconciliationOnDemandCreate': return ifoodApiRequest.call(this, 'POST', '/v3/reconciliation-on-demand', body, q);
199
+ case 'financialReconciliationOnDemandStatus': return ifoodApiRequest.call(this, 'GET', `/v3/reconciliation-on-demand/${encodeURIComponent(p.id)}`, null, q);
200
+ case 'financialAnticipations': return ifoodApiRequest.call(this, 'GET', '/v3/anticipations', null, compactQuery(Object.assign({ merchantId: p.merchantId }, q)));
201
+ case 'financialCustom': return ifoodApiRequest.call(this, p.customMethod, p.customPath, body, q);
202
+
203
+ case 'catalogList': return ifoodApiRequest.call(this, 'GET', replace('/catalog/v2.0/merchants/{merchantId}/catalogs'), null, q);
204
+ case 'catalogCategories': return ifoodApiRequest.call(this, 'GET', replace('/catalog/v2.0/merchants/{merchantId}/catalogs/{id}/categories'), null, q);
205
+ case 'catalogItems': return ifoodApiRequest.call(this, 'GET', replace('/catalog/v2.0/merchants/{merchantId}/catalogs/{id}/items'), null, q);
206
+ case 'catalogCustom': return ifoodApiRequest.call(this, p.customMethod, `/catalog/v2.0/${p.customPath.replace(/^\//, '')}`, body, q);
207
+
208
+ case 'logisticsOrder': return ifoodApiRequest.call(this, 'GET', replace('/logistics/v1.0/orders/{id}'), null, q);
209
+ case 'logisticsCustom': return ifoodApiRequest.call(this, p.customMethod, `/logistics/v1.0/${p.customPath.replace(/^\//, '')}`, body, q);
210
+
211
+ case 'shippingQuote': return ifoodApiRequest.call(this, 'POST', '/shipping/v1.0/quote', body, q);
212
+ case 'shippingCreate': return ifoodApiRequest.call(this, 'POST', '/shipping/v1.0/deliveries', body, q);
213
+ case 'shippingGet': return ifoodApiRequest.call(this, 'GET', replace('/shipping/v1.0/deliveries/{id}'), null, q);
214
+ case 'shippingCancel': return ifoodApiRequest.call(this, 'POST', replace('/shipping/v1.0/deliveries/{id}/cancel'), body, q);
215
+ case 'shippingCustom': return ifoodApiRequest.call(this, p.customMethod, `/shipping/v1.0/${p.customPath.replace(/^\//, '')}`, body, q);
216
+
217
+ case 'reviewList': return ifoodApiRequest.call(this, 'GET', replace('/review/v2.0/merchants/{merchantId}/reviews'), null, q);
218
+ case 'reviewGet': return ifoodApiRequest.call(this, 'GET', replace('/review/v2.0/merchants/{merchantId}/reviews/{id}'), null, q);
219
+ case 'reviewReply': return ifoodApiRequest.call(this, 'POST', replace('/review/v2.0/merchants/{merchantId}/reviews/{id}/reply'), body, q);
220
+ case 'reviewCustom': return ifoodApiRequest.call(this, p.customMethod, `/review/v2.0/${p.customPath.replace(/^\//, '')}`, body, q);
221
+ default:
222
+ throw new Error(`Operação não implementada: ${operation}`);
223
+ }
224
+ }
225
+ }
226
+
227
+ exports.IfoodCompleto = IfoodCompleto;
@@ -0,0 +1,18 @@
1
+ {
2
+ "node": "n8n-nodes-ifood-completo.ifoodCompleto",
3
+ "nodeVersion": "1.0",
4
+ "codexVersion": "1.0",
5
+ "categories": ["Finance", "Sales", "Delivery"],
6
+ "resources": {
7
+ "credentialDocumentation": [
8
+ {
9
+ "url": "https://developer.ifood.com.br/"
10
+ }
11
+ ],
12
+ "primaryDocumentation": [
13
+ {
14
+ "url": "https://developer.ifood.com.br/"
15
+ }
16
+ ]
17
+ }
18
+ }
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "n8n-nodes-ifood-completo",
3
+ "version": "0.1.0",
4
+ "description": "Nós customizados do n8n para Merchant API iFood: autenticação, lojas, eventos, pedidos, financeiro, catálogo, logística, shipping e avaliações.",
5
+ "keywords": [
6
+ "n8n-community-node-package",
7
+ "n8n",
8
+ "ifood",
9
+ "merchant-api",
10
+ "conciliacao",
11
+ "delivery"
12
+ ],
13
+ "license": "UNLICENSED",
14
+ "homepage": "https://merchant-api.ifood.com.br/",
15
+ "author": "BK Manaus",
16
+ "main": "index.js",
17
+ "files": [
18
+ "credentials",
19
+ "helpers",
20
+ "nodes",
21
+ "README.md",
22
+ "CHANGELOG.md",
23
+ "PUBLISHING.md"
24
+ ],
25
+ "scripts": {
26
+ "lint": "n8n-node lint",
27
+ "build": "node -e \"console.log('Pacote JavaScript pronto para n8n. Nenhum build necessario.')\"",
28
+ "dev": "n8n-node dev",
29
+ "pack:local": "npm pack",
30
+ "validate": "node scripts/validate-package.js",
31
+ "publish:dry-run": "npm publish --dry-run",
32
+ "release:pack": "npm pack",
33
+ "prepublishOnly": "npm run validate && npm run build"
34
+ },
35
+ "dependencies": {},
36
+ "devDependencies": {
37
+ "@n8n/node-cli": "latest"
38
+ },
39
+ "peerDependencies": {
40
+ "n8n-workflow": "*"
41
+ },
42
+ "n8n": {
43
+ "credentials": [
44
+ "credentials/IfoodCompletoApi.credentials.js"
45
+ ],
46
+ "nodes": [
47
+ "nodes/IfoodCompleto/IfoodCompleto.node.js"
48
+ ]
49
+ },
50
+ "engines": {
51
+ "node": ">=18.10",
52
+ "npm": ">=8"
53
+ },
54
+ "publishConfig": {
55
+ "access": "public"
56
+ }
57
+ }