http-sankhya 1.0.3 → 1.0.5

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 CHANGED
@@ -44,7 +44,7 @@ await sankhya.login();
44
44
 
45
45
  ### 1. loadRecords (Buscar Múltiplos Registros)
46
46
 
47
- Busca uma lista de registros com suporte a filtros, paginação e seleção de campos.
47
+ Busca uma lista de registros com suporte a filtros, paginação e seleção de campos. Este método utiliza o serviço `CRUDServiceProvider.loadRecords`.
48
48
 
49
49
  #### Exemplo Básico
50
50
  ```typescript
@@ -54,6 +54,12 @@ const produtos = await sankhya.loadRecords({
54
54
  expression: "ATIVO = 'S'" // Filtro SQL-like
55
55
  }
56
56
  });
57
+
58
+ // Retorno Exemplo:
59
+ // [
60
+ // { "CODGRUPOPROD": "100", "DESCRGRUPOPROD": "GERAL", "ATIVO": "S" },
61
+ // { "CODGRUPOPROD": "101", "DESCRGRUPOPROD": "MATERIA PRIMA", "ATIVO": "S" }
62
+ // ]
57
63
  ```
58
64
 
59
65
  #### Exemplo com Paginação e Seleção de Campos
@@ -72,6 +78,12 @@ const parceiros = await sankhya.loadRecords({
72
78
  }
73
79
  }
74
80
  });
81
+
82
+ // Retorno Exemplo:
83
+ // [
84
+ // { "CODPARC": "200", "NOMEPARC": "CLIENTE EXEMPLO", "CGC_CPF": "123.456.789-00", "EMAIL": "cliente@email.com" },
85
+ // { "CODPARC": "201", "NOMEPARC": "OUTRO CLIENTE", "CGC_CPF": "987.654.321-00", "EMAIL": "outro@email.com" }
86
+ // ]
75
87
  ```
76
88
 
77
89
  #### Exemplo com Campos de Apresentação
@@ -85,13 +97,23 @@ const vendas = await sankhya.loadRecords({
85
97
  expression: "DTNEG >= '01/01/2024'"
86
98
  }
87
99
  });
100
+
101
+ // Retorno Exemplo:
102
+ // [
103
+ // {
104
+ // "NUNOTA": "100",
105
+ // "DTNEG": "01/01/2024",
106
+ // "CODPARC": "200",
107
+ // "Parceiro_NOMEPARC": "CLIENTE EXEMPLO"
108
+ // }
109
+ // ]
88
110
  ```
89
111
 
90
112
  ---
91
113
 
92
114
  ### 2. loadRecord (Buscar Registro Único)
93
115
 
94
- Busca um único registro específico, geralmente pela Chave Primária (PK).
116
+ Busca um único registro específico, geralmente pela Chave Primária (PK). Este método utiliza o serviço `CRUDServiceProvider.loadRecord`.
95
117
 
96
118
  ```typescript
97
119
  const produto = await sankhya.loadRecord({
@@ -110,13 +132,21 @@ const produto = await sankhya.loadRecord({
110
132
 
111
133
  console.log(produto);
112
134
  // Saída: { CODPROD: "1005", DESCRPROD: "PRODUTO TESTE", ... }
135
+
136
+ // Retorno Exemplo Completo:
137
+ // {
138
+ // "CODPROD": "1005",
139
+ // "DESCRPROD": "PRODUTO TESTE",
140
+ // "ATIVO": "S",
141
+ // "PRECO": "50.00"
142
+ // }
113
143
  ```
114
144
 
115
145
  ---
116
146
 
117
147
  ### 3. saveRecord (Criar ou Atualizar Registro)
118
148
 
119
- Cria ou atualiza registros. A biblioteca formata automaticamente o payload do objeto `localFields` para o padrão exigido pelo Sankhya.
149
+ Cria ou atualiza registros. Este método é específico para manipulações que utilizam o serviço `CRUDServiceProvider.saveRecord`. A biblioteca formata automaticamente o payload do objeto `localFields` para o padrão exigido pelo Sankhya.
120
150
 
121
151
  #### Criar Novo Registro
122
152
  Para criar, omita a Chave Primária (se for auto-incremental) ou passe os valores necessários.
@@ -136,6 +166,12 @@ const novoGrupo = await sankhya.saveRecord({
136
166
  }
137
167
  }
138
168
  });
169
+
170
+ // Retorno Exemplo:
171
+ // {
172
+ // "CODGRUPOPROD": "161000",
173
+ // "DESCRGRUPOPROD": "NOVO GRUPO 2024"
174
+ // }
139
175
  ```
140
176
 
141
177
  #### Atualizar Registro Existente
@@ -152,17 +188,41 @@ const atualizacao = await sankhya.saveRecord({
152
188
  CODGRUPOPROD: "20310006" // Chave Primária (PK) para identificação do registro
153
189
  }
154
190
  });
191
+
192
+ #### Retorno Exemplo (Sucesso)
193
+ Tanto na criação quanto na atualização, a biblioteca processa a resposta e retorna um objeto limpo com os campos solicitados no `fieldset`.
194
+
195
+ ```json
196
+ {
197
+ "CODGRUPOPROD": "160700",
198
+ "DESCRGRUPOPROD": "NOME ATUALIZADO",
199
+ "ATIVO": "N"
200
+ }
201
+ ```
202
+
203
+ #### Retorno Exemplo (Falha)
204
+ Caso ocorra algum erro (status '0'), a biblioteca retorna o objeto de resposta original contendo a mensagem de erro.
205
+
206
+ ```json
207
+ {
208
+ "serviceName": "CRUDServiceProvider.saveRecord",
209
+ "status": "0",
210
+ "pendingPrinting": "false",
211
+ "transactionId": "123456789",
212
+ "statusMessage": "Erro: O registro já existe ou violação de restrição de integridade."
213
+ }
214
+ ```
155
215
  ```
156
216
 
157
217
  ---
158
218
 
159
- ### 4. Execução de Serviço Genérico (execService)
219
+ ### 4. Execução de Serviço Mge (execServiceMge)
160
220
 
161
- Para endpoints que não sejam CRUD padrão (ex: executar Stored Procedures, ações de workflow, ou consultas de metadados), use `execService`.
221
+ Para endpoints que não sejam CRUD padrão (ex: executar Stored Procedures, ações de workflow, ou consultas de metadados), use `execServiceMge`. Este método utiliza o endpoint `/gateway/v1/mge/service.sbr`.
162
222
 
163
223
  #### Exemplo: Consultar Estoque (Serviço Hipotético)
164
224
  ```typescript
165
- const estoque = await sankhya.execService({
225
+ const estoque = await sankhya.execServiceMge({
166
226
  serviceName: 'EstoqueSP.getEstoque',
167
227
  requestBody: {
168
228
  codProd: '1005',
@@ -175,7 +235,7 @@ const estoque = await sankhya.execService({
175
235
  Embora exista o método `.delete()`, algumas operações de exclusão no Sankhya são feitas via serviços específicos.
176
236
 
177
237
  ```typescript
178
- await sankhya.execService({
238
+ await sankhya.execServiceMge({
179
239
  serviceName: 'CRUDServiceProvider.removeRecord',
180
240
  requestBody: {
181
241
  entity: {
@@ -186,6 +246,83 @@ await sankhya.execService({
186
246
  }
187
247
  }
188
248
  });
249
+
250
+ // Retorno Exemplo:
251
+ // {
252
+ // "serviceName": "CRUDServiceProvider.removeRecord",
253
+ // "status": "1",
254
+ // "pendingPrinting": "false",
255
+ // "transactionId": "123456789",
256
+ // "responseBody": {}
257
+ // }
258
+ ```
259
+
260
+ ---
261
+
262
+ ### 5. Execução de Serviço MgeCom (execServiceMgeCom)
263
+
264
+ Para serviços diversos do Sankhya que utilizam o endpoint **mgecom** (`/gateway/v1/mgecom/service.sbr`), como inclusão de notas, operações comerciais, etc. Este método recebe o `serviceName` e o `requestBody` em **formato JSON simples** e transforma automaticamente todos os valores primitivos (strings/números) para o formato `{ "$": "valor" }` exigido pelo Sankhya.
265
+
266
+ > **Nota:** Diferente do `execServiceMge` que usa `/gateway/v1/mge/service.sbr`, este método envia as requisições para `/gateway/v1/mgecom/service.sbr`.
267
+
268
+ #### Exemplo: Incluir Pedido de Venda / Nota (CACSP.incluirNota)
269
+ ```typescript
270
+ const nota = await sankhya.execServiceMgeCom('CACSP.incluirNota', {
271
+ nota: {
272
+ cabecalho: {
273
+ CODPARC: "3",
274
+ DTNEG: "03/07/2023",
275
+ CODTIPOPER: "1718",
276
+ CODTIPVENDA: "34",
277
+ CODVEND: "0",
278
+ CODEMP: "15",
279
+ TIPMOV: "V", // V = Venda | C=Compra | D=Devolução | etc.
280
+ CODNAT: "10101002",
281
+ CODCENCUS: "10600200",
282
+ SERIE: "14"
283
+ },
284
+ itens: {
285
+ INFORMARPRECO: "True",
286
+ item: [
287
+ {
288
+ CODPROD: "6",
289
+ QTDNEG: "1",
290
+ CODLOCALORIG: "0",
291
+ CODVOL: "SV",
292
+ PERCDESC: "0",
293
+ VLRUNIT: "81.75"
294
+ }
295
+ ]
296
+ }
297
+ }
298
+ });
299
+ ```
300
+
301
+ A biblioteca transforma automaticamente o payload acima para o formato exigido pelo Sankhya antes do envio:
302
+
303
+ ```json
304
+ {
305
+ "serviceName": "CACSP.incluirNota",
306
+ "requestBody": {
307
+ "nota": {
308
+ "cabecalho": {
309
+ "CODPARC": { "$": "3" },
310
+ "DTNEG": { "$": "03/07/2023" },
311
+ "CODTIPOPER": { "$": "1718" }
312
+ },
313
+ "itens": {
314
+ "INFORMARPRECO": { "$": "True" },
315
+ "item": [
316
+ {
317
+ "CODPROD": { "$": "6" },
318
+ "QTDNEG": { "$": "1" },
319
+ "CODVOL": { "$": "SV" }
320
+ }
321
+ ]
322
+ }
323
+ }
324
+ }
325
+ }
189
326
  ```
190
327
 
191
328
  ## Funcionalidades
@@ -194,4 +331,5 @@ await sankhya.execService({
194
331
  - *LoadRecords*: Retorna `Array<Objeto>`.
195
332
  - *LoadRecord*: Retorna `Objeto` único (lida com ausência de metadados).
196
333
  - **Transformação de Payload**: O método `saveRecord` aceita objetos simples JS (ex: `{ CAMPO: "Valor" }`) e os converte automaticamente para `{ CAMPO: { "$": "Valor" } }`.
334
+ - **Transformação Profunda de Payload**: O método `execServiceMgeCom` transforma recursivamente todos os valores primitivos de um objeto JSON aninhado para o formato `{ "$": "valor" }`, incluindo arrays e sub-objetos.
197
335
  - **Tipagem TypeScript**: Suporte completo a interfaces para garantir segurança de tipo no desenvolvimento.
package/dist/Sankhya.d.ts CHANGED
@@ -40,9 +40,51 @@ export declare class Sankhya {
40
40
  put(path: string, body?: Record<string, any>, queryParam?: Record<string, any>, headers?: Record<string, any>): Promise<any>;
41
41
  patch(path: string, body?: Record<string, any>, queryParam?: Record<string, any>, headers?: Record<string, any>): Promise<any>;
42
42
  delete(path: string, queryParam?: Record<string, any>, headers?: Record<string, any>): Promise<any>;
43
- execService(options: ExecServiceOptions, outputType?: 'json' | 'xml'): Promise<any>;
43
+ execServiceMge(options: ExecServiceOptions, outputType?: 'json' | 'xml'): Promise<any>;
44
44
  loadRecords({ rootEntity, includePresentationFields, offsetPage, criteria, entity }: LoadRecordsOptions, outputType?: 'json' | 'xml'): Promise<any>;
45
45
  loadRecord({ rootEntity, includePresentationFields, criteria, entity, rows }: LoadRecordsOptions, outputType?: 'json' | 'xml'): Promise<any>;
46
46
  saveRecord({ rootEntity, includePresentationFields, localFields, key, entity }: SaveRecordOptions, outputType?: 'json' | 'xml'): Promise<any>;
47
+ /**
48
+ * Executa serviços diversos do Sankhya via endpoint mgecom.
49
+ * Recebe o serviceName e o requestBody em formato JSON simples,
50
+ * transformando automaticamente todos os valores primitivos para { "$": "valor" }.
51
+ *
52
+ * Endpoint: /gateway/v1/mgecom/service.sbr
53
+ *
54
+ * @example
55
+ * ```typescript
56
+ * // Exemplo: Inclusão de Pedido de Venda
57
+ * const nota = await sankhya.execServiceMgeCom('CACSP.incluirNota', {
58
+ * nota: {
59
+ * cabecalho: {
60
+ * CODPARC: "3",
61
+ * DTNEG: "03/07/2023",
62
+ * CODTIPOPER: "1718",
63
+ * CODTIPVENDA: "34",
64
+ * CODVEND: "0",
65
+ * CODEMP: "15",
66
+ * TIPMOV: "P",
67
+ * CODNAT: "10101002",
68
+ * CODCENCUS: "10600200",
69
+ * SERIE: "14"
70
+ * },
71
+ * itens: {
72
+ * INFORMARPRECO: "True",
73
+ * item: [
74
+ * {
75
+ * CODPROD: "6",
76
+ * QTDNEG: "1",
77
+ * CODLOCALORIG: "0",
78
+ * CODVOL: "SV",
79
+ * PERCDESC: "0",
80
+ * VLRUNIT: "81.75"
81
+ * }
82
+ * ]
83
+ * }
84
+ * }
85
+ * });
86
+ * ```
87
+ */
88
+ execServiceMgeCom(serviceName: string, requestBody: Record<string, any>, outputType?: 'json' | 'xml'): Promise<any>;
47
89
  private isEmptyObject;
48
90
  }
package/dist/Sankhya.js CHANGED
@@ -94,7 +94,7 @@ class Sankhya {
94
94
  return response.data;
95
95
  }
96
96
  // Sankhya Specific Methods
97
- async execService(options, outputType = 'json') {
97
+ async execServiceMge(options, outputType = 'json') {
98
98
  // Standard Sankhya Service URL pattern: /mge/service.sbr?serviceName=...&outputType=json
99
99
  const { serviceName, requestBody } = options;
100
100
  // Construct the wrapper expected by Sankhya JSON API
@@ -110,7 +110,7 @@ class Sankhya {
110
110
  }, {});
111
111
  }
112
112
  async loadRecords({ rootEntity, includePresentationFields = 'N', offsetPage = 0, criteria = {}, entity = {} }, outputType = 'json') {
113
- return this.execService({
113
+ return this.execServiceMge({
114
114
  serviceName: 'CRUDServiceProvider.loadRecords',
115
115
  requestBody: {
116
116
  dataSet: {
@@ -125,7 +125,7 @@ class Sankhya {
125
125
  }, outputType);
126
126
  }
127
127
  async loadRecord({ rootEntity, includePresentationFields = 'N', criteria = {}, entity = {}, rows = {} }, outputType = 'json') {
128
- return this.execService({
128
+ return this.execServiceMge({
129
129
  serviceName: 'CRUDServiceProvider.loadRecord',
130
130
  requestBody: {
131
131
  dataSet: {
@@ -140,7 +140,7 @@ class Sankhya {
140
140
  }, outputType);
141
141
  }
142
142
  async saveRecord({ rootEntity, includePresentationFields = 'N', localFields = {}, key = {}, entity = {} }, outputType = 'json') {
143
- return this.execService({
143
+ return this.execServiceMge({
144
144
  serviceName: 'CRUDServiceProvider.saveRecord',
145
145
  requestBody: {
146
146
  dataSet: {
@@ -156,6 +156,59 @@ class Sankhya {
156
156
  outputType
157
157
  }, outputType);
158
158
  }
159
+ /**
160
+ * Executa serviços diversos do Sankhya via endpoint mgecom.
161
+ * Recebe o serviceName e o requestBody em formato JSON simples,
162
+ * transformando automaticamente todos os valores primitivos para { "$": "valor" }.
163
+ *
164
+ * Endpoint: /gateway/v1/mgecom/service.sbr
165
+ *
166
+ * @example
167
+ * ```typescript
168
+ * // Exemplo: Inclusão de Pedido de Venda
169
+ * const nota = await sankhya.execServiceMgeCom('CACSP.incluirNota', {
170
+ * nota: {
171
+ * cabecalho: {
172
+ * CODPARC: "3",
173
+ * DTNEG: "03/07/2023",
174
+ * CODTIPOPER: "1718",
175
+ * CODTIPVENDA: "34",
176
+ * CODVEND: "0",
177
+ * CODEMP: "15",
178
+ * TIPMOV: "P",
179
+ * CODNAT: "10101002",
180
+ * CODCENCUS: "10600200",
181
+ * SERIE: "14"
182
+ * },
183
+ * itens: {
184
+ * INFORMARPRECO: "True",
185
+ * item: [
186
+ * {
187
+ * CODPROD: "6",
188
+ * QTDNEG: "1",
189
+ * CODLOCALORIG: "0",
190
+ * CODVOL: "SV",
191
+ * PERCDESC: "0",
192
+ * VLRUNIT: "81.75"
193
+ * }
194
+ * ]
195
+ * }
196
+ * }
197
+ * });
198
+ * ```
199
+ */
200
+ async execServiceMgeCom(serviceName, requestBody, outputType = 'json') {
201
+ const transformedBody = SankhyaHelper_1.SankhyaHelper.transformDeepFields(requestBody);
202
+ const payload = {
203
+ serviceName,
204
+ requestBody: transformedBody
205
+ };
206
+ const response = await this.post('/gateway/v1/mgecom/service.sbr', payload, {
207
+ serviceName,
208
+ outputType
209
+ }, { 'Content-Type': 'application/json' });
210
+ return SankhyaHelper_1.SankhyaHelper.flattenMgeComResponse(response);
211
+ }
159
212
  isEmptyObject(obj) {
160
213
  return obj != null &&
161
214
  obj.constructor === Object &&
@@ -6,6 +6,22 @@ export declare class SankhyaHelper {
6
6
  static processResponse(response: any, options?: {
7
7
  serviceName?: string;
8
8
  }): any;
9
+ /**
10
+ * Remove recursivamente os wrappers { "$": "valor" } do retorno do Sankhya,
11
+ * retornando um JSON limpo e amigável.
12
+ * Utilizado para tratar retornos do endpoint mgecom (ex: CACSP.incluirNota).
13
+ */
14
+ static flattenMgeComResponse(obj: any): any;
15
+ /**
16
+ * Transforma recursivamente todos os valores primitivos (string/number) de um objeto
17
+ * para o formato Sankhya { "$": valor }, percorrendo objetos e arrays aninhados.
18
+ *
19
+ * Strings que são "irmãs" de arrays no mesmo objeto NÃO são encapsuladas,
20
+ * pois representam atributos XML (ex: INFORMARPRECO em "itens").
21
+ *
22
+ * Ex: { nota: { cabecalho: { CAMPO: "VALOR" } } } -> { nota: { cabecalho: { CAMPO: { "$": "VALOR" } } } }
23
+ */
24
+ static transformDeepFields(obj: any): any;
9
25
  /**
10
26
  * Transforma um objeto simples de chave/valor para o formato do Sankhya
11
27
  * Ex: { CAMPO: "VALOR" } -> { CAMPO: { "$": "VALOR" } }
@@ -22,6 +22,83 @@ class SankhyaHelper {
22
22
  return response;
23
23
  }
24
24
  }
25
+ /**
26
+ * Remove recursivamente os wrappers { "$": "valor" } do retorno do Sankhya,
27
+ * retornando um JSON limpo e amigável.
28
+ * Utilizado para tratar retornos do endpoint mgecom (ex: CACSP.incluirNota).
29
+ */
30
+ static flattenMgeComResponse(obj) {
31
+ if (obj === null || obj === undefined) {
32
+ return obj;
33
+ }
34
+ // Se for um objeto com apenas a chave "$", extrai o valor
35
+ if (typeof obj === 'object' && !Array.isArray(obj) && '$' in obj && Object.keys(obj).length === 1) {
36
+ return obj.$;
37
+ }
38
+ // Se for array, aplica recursivamente em cada elemento
39
+ if (Array.isArray(obj)) {
40
+ return obj.map(item => this.flattenMgeComResponse(item));
41
+ }
42
+ // Se for objeto, aplica recursivamente em cada propriedade
43
+ if (typeof obj === 'object') {
44
+ const result = {};
45
+ for (const key of Object.keys(obj)) {
46
+ result[key] = this.flattenMgeComResponse(obj[key]);
47
+ }
48
+ return result;
49
+ }
50
+ return obj;
51
+ }
52
+ /**
53
+ * Transforma recursivamente todos os valores primitivos (string/number) de um objeto
54
+ * para o formato Sankhya { "$": valor }, percorrendo objetos e arrays aninhados.
55
+ *
56
+ * Strings que são "irmãs" de arrays no mesmo objeto NÃO são encapsuladas,
57
+ * pois representam atributos XML (ex: INFORMARPRECO em "itens").
58
+ *
59
+ * Ex: { nota: { cabecalho: { CAMPO: "VALOR" } } } -> { nota: { cabecalho: { CAMPO: { "$": "VALOR" } } } }
60
+ */
61
+ static transformDeepFields(obj) {
62
+ // Campos com valor null ou undefined são tratados como placeholders (ex: PKs)
63
+ // e enviados como objeto vazio {} no formato Sankhya
64
+ if (obj === null || obj === undefined) {
65
+ return {};
66
+ }
67
+ // Se for string ou number, transforma para { "$": valor }
68
+ // (este caso é chamado recursivamente; a decisão de NÃO transformar
69
+ // é feita no nível do objeto pai, abaixo)
70
+ if (typeof obj === 'string' || typeof obj === 'number') {
71
+ return { $: String(obj) };
72
+ }
73
+ // Se for array, aplica recursivamente em cada elemento
74
+ if (Array.isArray(obj)) {
75
+ return obj.map(item => this.transformDeepFields(item));
76
+ }
77
+ // Se já estiver no formato { "$": ... }, mantém como está
78
+ if (typeof obj === 'object' && '$' in obj && Object.keys(obj).length === 1) {
79
+ return obj;
80
+ }
81
+ // Se for objeto, aplica recursivamente em cada propriedade
82
+ if (typeof obj === 'object') {
83
+ const keys = Object.keys(obj);
84
+ // Verifica se o objeto possui algum filho que é array.
85
+ // Se sim, strings neste nível são atributos XML e NÃO devem ser encapsuladas.
86
+ const hasArrayChild = keys.some(k => Array.isArray(obj[k]));
87
+ const transformed = {};
88
+ for (const key of keys) {
89
+ const value = obj[key];
90
+ if (hasArrayChild && (typeof value === 'string' || typeof value === 'number')) {
91
+ // Atributo XML: mantém como string pura
92
+ transformed[key] = value;
93
+ }
94
+ else {
95
+ transformed[key] = this.transformDeepFields(value);
96
+ }
97
+ }
98
+ return transformed;
99
+ }
100
+ return obj;
101
+ }
25
102
  /**
26
103
  * Transforma um objeto simples de chave/valor para o formato do Sankhya
27
104
  * Ex: { CAMPO: "VALOR" } -> { CAMPO: { "$": "VALOR" } }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "http-sankhya",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "Biblioteca TypeScript para integração com ERP Sankhya",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",