From b1aae3304b922f0dccc63b477f6aec13854270f1 Mon Sep 17 00:00:00 2001 From: eduardoestevao-appsoluti Date: Wed, 10 Sep 2025 16:56:11 -0300 Subject: [PATCH 01/20] Add endpoint to retrieve similar products and implement corresponding service method --- src/sales/sales/sales.controller.ts | 14 +++++++ src/sales/sales/sales.service.ts | 60 +++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/src/sales/sales/sales.controller.ts b/src/sales/sales/sales.controller.ts index 0e01487..a67bf88 100644 --- a/src/sales/sales/sales.controller.ts +++ b/src/sales/sales/sales.controller.ts @@ -176,6 +176,20 @@ export class SalesController { } } + + @Get('product/simil/:id') + @ApiOperation({ summary: 'Get products similar' }) + @ApiParam({ name: 'id', description: 'Product ID' }) + async getProductSimil(@Headers() headers, @Param('id') id: number) { + try { + const { store } = this.extractPaginationParams(headers); + return await this.salesService.GetProductsSimil(store, id); + } catch (e) { + throw new HttpException(e.message, HttpStatus.BAD_REQUEST); + } + } + + @Get('stock/:storeid/:id') @ApiOperation({ summary: 'Get product stock information' }) @ApiParam({ name: 'storeid', description: 'Store ID' }) diff --git a/src/sales/sales/sales.service.ts b/src/sales/sales/sales.service.ts index a9ffd36..c0ac921 100644 --- a/src/sales/sales/sales.service.ts +++ b/src/sales/sales/sales.service.ts @@ -851,6 +851,66 @@ export class SalesService { } } + async GetProductsSimil(store: string, id: number) { + const connectionDb = new Connection(connectionOptions); + await connectionDb.connect(); + const queryRunner = connectionDb.createQueryRunner(); + await queryRunner.connect(); + try { + const sql = `SELECT esvlistaprodutos.CODPROD as "idProduct" + ,esvlistaprodutos.SEQ as "seq" + ,esvlistaprodutos.DESCRICAO as "smallDescription" + ,esvlistaprodutos.NOMEECOMMERCE as "title" + ,esvlistaprodutos.CODFAB as "idProvider" + ,esvlistaprodutos.CODAUXILIAR as "ean" + ,esvlistaprodutos.TIPOPRODUTO as "productType" + ,esvlistaprodutos.DADOSTECNICOS as "technicalData" + ,esvlistaprodutos.INFORMACOESTECNICAS as "description" + ,esvlistaprodutos.URLIMAGEM as "urlImage" + ,esvlistaprodutos.NOMEMARCA as "brand" + ,esvlistaprodutos.NOMEDEPARTAMENTO as "department" + ,esvlistaprodutos.NOMESECAO as "section" + ,esvlistaprodutos.NOMECATEGORIA as "category" + ,esvlistaprodutos.NOMEFORNECEDOR as "supplier" + ,esvlistaprodutos.CODIGOFILIAL as "store" + ,esvlistaprodutos.CLASSEVENDA as "saleAbc" + ,esvlistaprodutos.CLASSEESTOQUE as "stockAbc" + ,esvlistaprodutos.FORALINHA as "outLine" + ,esvlistaprodutos.PRECOVENDA as "listPrice" + ,esvlistaprodutos.PRECOPROMOCIONAL as "salePrice" + ,esvlistaprodutos.PRECOPROMOCIONAL as "salePromotion" + ,esvlistaprodutos.PERCENTUALDESCONTO as"offPercent" + ,esvlistaprodutos.QTESTOQUE_DISPONIVEL as "stock" + ,esvlistaprodutos.QTCAIXAS as "boxStock" + ,esvlistaprodutos.ESTOQUE_DISP_LOJA as "store_stock" + ,esvlistaprodutos.ESTOQUE_DISP_CAIXA_LOJA as "store_boxStock" + ,esvlistaprodutos.ESTOQUE_DISP_LOJA as "store_stock" + ,esvlistaprodutos.ESTOQUE_DISP_CAIXA_LOJA as "store_boxStock" + ,esvlistaprodutos.MULTIPLO as "mutiple" + ,esvlistaprodutos.UNIDADE as "unity" + ,esvlistaprodutos.URLDEPARTAMENTO as "urlDepartment" + ,esvlistaprodutos.URLSECAO as "urlSection" + ,esvlistaprodutos.PRODUTO_COM_REDUCAO_PRECO as "downPrice" + ,esvlistaprodutos.PRODUTO_EM_CAMPANHA as "compaing" + ,esvlistaprodutos.BASETINTOMETRICO as "base" + ,esvlistaprodutos.QUANTIDADE_ESTOQUE_GERAL as "full_stock" + FROM ESVLISTAPRODUTOS, PCPRODSIMIL + WHERE ESVLISTAPRODUTOS.CODPROD = PCPRODSIMIL.CODSIMIL + AND PCPRODSIMIL.CODPROD = ${id} + AND ESVLISTAPRODUTOS.CODFILIAL = '${store}' + ORDER BY REPLACE(esvlistaprodutos.DESCRICAO,'#', '')`; + let products: SalesProduct[] = await queryRunner.query(sql); + + products = this.createListImages(products); + return products; + } catch (error) { + throw error; + } finally { + await queryRunner.release(); + await connectionDb.close(); + } + } + async GetStocks(storeId: string, id: number) { const connectionDb = new Connection(connectionOptions); await connectionDb.connect(); -- 2.49.1 From f32a3fd40f490bf24bf2877ab3b463eac8437c7b Mon Sep 17 00:00:00 2001 From: eduardoestevao-appsoluti Date: Wed, 17 Sep 2025 09:48:07 -0300 Subject: [PATCH 02/20] Add 'similar' product selection to sales queries in SalesService --- src/sales/sales/sales.service.ts | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/sales/sales/sales.service.ts b/src/sales/sales/sales.service.ts index c0ac921..5d410e0 100644 --- a/src/sales/sales/sales.service.ts +++ b/src/sales/sales/sales.service.ts @@ -77,7 +77,8 @@ export class SalesService { esvlistaprodutos.LETRABASETINTOMETRICO as "letter", esvlistaprodutos.LINHATINTOMETRICO as "line", esvlistaprodutos.LITRAGEM as "can", - esvlistaprodutos.QUANTIDADE_ESTOQUE_GERAL as "full_stock" + esvlistaprodutos.QUANTIDADE_ESTOQUE_GERAL as "full_stock", + esvlistaprodutos.TEM_PRODUTO_SIMILAR as "similar" FROM ESVLISTAPRODUTOS WHERE 1 = 1`; @@ -127,6 +128,7 @@ export class SalesService { .addSelect("\"esvlistaprodutos\".LINHATINTOMETRICO", "line") .addSelect("\"esvlistaprodutos\".LITRAGEM", "can") .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") + .addSelect("\"esvlistaprodutos\".TEM_PRODUTO_SIMILAR", "similar") .where("UPPER(\"esvlistaprodutos\".CODFAB) LIKE '%'||REPLACE(:description, '@', '%')||'%'", { description }) .andWhere("(\"esvlistaprodutos\".codfilial = :codfilial OR :codfilial = '99')", { codfilial: store }) .andWhere("(\"esvlistaprodutos\".produto_com_reducao_preco = :produtoComReducaoPreco OR :produtoComReducaoPreco = 'N')", @@ -184,6 +186,7 @@ export class SalesService { .addSelect("\"esvlistaprodutos\".LINHATINTOMETRICO", "line") .addSelect("\"esvlistaprodutos\".LITRAGEM", "can") .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") + .addSelect("\"esvlistaprodutos\".TEM_PRODUTO_SIMILAR", "similar") .where("UPPER(\"esvlistaprodutos\".descricao) LIKE '%'||REPLACE(:description, '@', '%')||'%'", { description }) .andWhere("(\"esvlistaprodutos\".codfilial = :codfilial OR :codfilial = '99')", { codfilial: store }) .andWhere("(\"esvlistaprodutos\".produto_com_reducao_preco = :produtoComReducaoPreco OR :produtoComReducaoPreco = 'N')", @@ -260,6 +263,7 @@ export class SalesService { .addSelect("\"esvlistaprodutos\".LINHATINTOMETRICO", "line") .addSelect("\"esvlistaprodutos\".LITRAGEM", "can") .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") + .addSelect("\"esvlistaprodutos\".TEM_PRODUTO_SIMILAR", "similar") .where("esvlistaprodutos.brand in (" + xbrands + ")") .andWhere("\"esvlistaprodutos\".URLCATEGORIA LIKE :urlCategoria||'%'", { urlCategoria: filter.urlCategory }) .andWhere("(\"esvlistaprodutos\".codfilial = :codfilial OR :codfilial = '99')", { codfilial: store }) @@ -324,6 +328,7 @@ export class SalesService { .addSelect("\"esvlistaprodutos\".LINHATINTOMETRICO", "line") .addSelect("\"esvlistaprodutos\".LITRAGEM", "can") .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") + .addSelect("\"esvlistaprodutos\".TEM_PRODUTO_SIMILAR", "similar") .where("(\"esvlistaprodutos\".codfilial = :codfilial OR :codfilial = '99')", { codfilial: store }) .andWhere("(\"esvlistaprodutos\".produto_com_reducao_preco = :produtoComReducaoPreco OR :produtoComReducaoPreco = 'N')", { produtoComReducaoPreco: (filter.markdown.toString() == 'true') ? 'S' : 'N' }) @@ -562,6 +567,7 @@ export class SalesService { .addSelect("\"esvlistaprodutos\".PRODUTO_EM_CAMPANHA", "compaing") .addSelect("\"esvlistaprodutos\".BASETINTOMETRICO", "base") .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") + .addSelect("\"esvlistaprodutos\".TEM_PRODUTO_SIMILAR", "similar") .where("esvlistaprodutos.idProduct = :id", { id: numbers }) .andWhere("\"esvlistaprodutos\".codfilial = :codfilial OR :codfilial = '99'", { codfilial: store }) .limit(pageSize) @@ -608,7 +614,8 @@ export class SalesService { .addSelect("\"esvlistaprodutos\".PRODUTO_COM_REDUCAO_PRECO", "downPrice") .addSelect("\"esvlistaprodutos\".PRODUTO_EM_CAMPANHA", "compaing") .addSelect("\"esvlistaprodutos\".BASETINTOMETRICO", "base") - .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") + .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") + .addSelect("\"esvlistaprodutos\".TEM_PRODUTO_SIMILAR", "similar") .where("esvlistaprodutos.CODAUXILIAR = :id", { id: numbers }) .andWhere("(\"esvlistaprodutos\".codfilial = :codfilial OR :codfilial = '99')", { codfilial: store }) .limit(pageSize) @@ -657,7 +664,8 @@ export class SalesService { .addSelect("\"esvlistaprodutos\".PRODUTO_COM_REDUCAO_PRECO", "downPrice") .addSelect("\"esvlistaprodutos\".PRODUTO_EM_CAMPANHA", "compaing") .addSelect("\"esvlistaprodutos\".BASETINTOMETRICO", "base") - .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") + .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") + .addSelect("\"esvlistaprodutos\".TEM_PRODUTO_SIMILAR", "similar") .where("UPPER(esvlistaprodutos.CODFAB) like REPLACE(:description, '@', '%')", { description }) .andWhere("\"esvlistaprodutos\".codfilial = :codfilial OR :codfilial = '99'", { codfilial: store }) .limit(pageSize) @@ -703,7 +711,8 @@ export class SalesService { .addSelect("\"esvlistaprodutos\".PRODUTO_COM_REDUCAO_PRECO", "downPrice") .addSelect("\"esvlistaprodutos\".PRODUTO_EM_CAMPANHA", "compaing") .addSelect("\"esvlistaprodutos\".BASETINTOMETRICO", "base") - .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") + .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") + .addSelect("\"esvlistaprodutos\".TEM_PRODUTO_SIMILAR", "similar") .where("UPPER(esvlistaprodutos.DESCRICAO) like REPLACE(:description, '@', '%')", { description }) .andWhere("\"esvlistaprodutos\".codfilial = :codfilial OR :codfilial = '99'", { codfilial: store }) .limit(pageSize) @@ -772,7 +781,8 @@ export class SalesService { .addSelect("\"esvlistaprodutos\".PRODUTO_COM_REDUCAO_PRECO", "downPrice") .addSelect("\"esvlistaprodutos\".PRODUTO_EM_CAMPANHA", "compaing") .addSelect("\"esvlistaprodutos\".BASETINTOMETRICO", "base") - .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") + .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") + .addSelect("\"esvlistaprodutos\".TEM_PRODUTO_SIMILAR", "similar") .where("esvlistaprodutos.idProduct = :id", { id: id }) .andWhere("\"esvlistaprodutos\".codfilial = :codfilial", { codfilial: store }) .orderBy("REPLACE(\"esvlistaprodutos\".DESCRICAO,'#', '')", "ASC") @@ -834,6 +844,7 @@ export class SalesService { ,esvlistaprodutos.PRODUTO_EM_CAMPANHA as "compaing" ,esvlistaprodutos.BASETINTOMETRICO as "base" ,esvlistaprodutos.QUANTIDADE_ESTOQUE_GERAL as "full_stock" + ,esvlistaprodutos.TEM_PRODUTO_SIMILAR as "similar" FROM ESVLISTAPRODUTOS, ESTCOMPREJUNTO WHERE ESVLISTAPRODUTOS.CODPROD = ESTCOMPREJUNTO.CODPROD AND ESTCOMPREJUNTO.CODPRODVENDA = ${id} @@ -894,6 +905,7 @@ export class SalesService { ,esvlistaprodutos.PRODUTO_EM_CAMPANHA as "compaing" ,esvlistaprodutos.BASETINTOMETRICO as "base" ,esvlistaprodutos.QUANTIDADE_ESTOQUE_GERAL as "full_stock" + ,esvlistaprodutos.TEM_PRODUTO_SIMILAR as "similar" FROM ESVLISTAPRODUTOS, PCPRODSIMIL WHERE ESVLISTAPRODUTOS.CODPROD = PCPRODSIMIL.CODSIMIL AND PCPRODSIMIL.CODPROD = ${id} @@ -1325,6 +1337,7 @@ export class SalesService { ' ,esvlistaprodutos.LINHATINTOMETRICO "line" ' + ' ,esvlistaprodutos.LITRAGEM "can" ' + ' ,esvlistaprodutos.QUANTIDADE_ESTOQUE_GERAL "full_stock" ' + + ' ,esvlistaprodutos.TEM_PRODUTO_SIMILAR "similar" ' + ' FROM esvlistaprodutos ' + ' WHERE 1 = 1'; -- 2.49.1 From 615c4353b8ebaefdd7749c771a4caac6a126bc18 Mon Sep 17 00:00:00 2001 From: eduardoestevao-appsoluti Date: Sat, 20 Sep 2025 11:40:40 -0300 Subject: [PATCH 03/20] Add 'type_campaing' selection to sales queries in SalesService --- src/sales/sales/sales.service.ts | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/sales/sales/sales.service.ts b/src/sales/sales/sales.service.ts index 5d410e0..0022357 100644 --- a/src/sales/sales/sales.service.ts +++ b/src/sales/sales/sales.service.ts @@ -78,9 +78,10 @@ export class SalesService { esvlistaprodutos.LINHATINTOMETRICO as "line", esvlistaprodutos.LITRAGEM as "can", esvlistaprodutos.QUANTIDADE_ESTOQUE_GERAL as "full_stock", - esvlistaprodutos.TEM_PRODUTO_SIMILAR as "similar" + esvlistaprodutos.TEM_PRODUTO_SIMILAR as "similar", + NVL(esvlistaprodutos.TIPO, 'SEM') as "type_campaing" FROM ESVLISTAPRODUTOS - WHERE 1 = 1`; + WHERE 1 = 1 `; if (filter && filter.text.length > 0) { const description = filter.text.toUpperCase(); @@ -129,6 +130,7 @@ export class SalesService { .addSelect("\"esvlistaprodutos\".LITRAGEM", "can") .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") .addSelect("\"esvlistaprodutos\".TEM_PRODUTO_SIMILAR", "similar") + .addSelect("\"esvlistaprodutos\".TIPO_CAMPANHA", "type_campaing") .where("UPPER(\"esvlistaprodutos\".CODFAB) LIKE '%'||REPLACE(:description, '@', '%')||'%'", { description }) .andWhere("(\"esvlistaprodutos\".codfilial = :codfilial OR :codfilial = '99')", { codfilial: store }) .andWhere("(\"esvlistaprodutos\".produto_com_reducao_preco = :produtoComReducaoPreco OR :produtoComReducaoPreco = 'N')", @@ -187,6 +189,7 @@ export class SalesService { .addSelect("\"esvlistaprodutos\".LITRAGEM", "can") .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") .addSelect("\"esvlistaprodutos\".TEM_PRODUTO_SIMILAR", "similar") + .addSelect("\"esvlistaprodutos\".TIPO_CAMPANHA", "type_campaing") .where("UPPER(\"esvlistaprodutos\".descricao) LIKE '%'||REPLACE(:description, '@', '%')||'%'", { description }) .andWhere("(\"esvlistaprodutos\".codfilial = :codfilial OR :codfilial = '99')", { codfilial: store }) .andWhere("(\"esvlistaprodutos\".produto_com_reducao_preco = :produtoComReducaoPreco OR :produtoComReducaoPreco = 'N')", @@ -264,6 +267,7 @@ export class SalesService { .addSelect("\"esvlistaprodutos\".LITRAGEM", "can") .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") .addSelect("\"esvlistaprodutos\".TEM_PRODUTO_SIMILAR", "similar") + .addSelect("\"esvlistaprodutos\".TIPO_CAMPANHA", "type_campaing") .where("esvlistaprodutos.brand in (" + xbrands + ")") .andWhere("\"esvlistaprodutos\".URLCATEGORIA LIKE :urlCategoria||'%'", { urlCategoria: filter.urlCategory }) .andWhere("(\"esvlistaprodutos\".codfilial = :codfilial OR :codfilial = '99')", { codfilial: store }) @@ -329,6 +333,7 @@ export class SalesService { .addSelect("\"esvlistaprodutos\".LITRAGEM", "can") .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") .addSelect("\"esvlistaprodutos\".TEM_PRODUTO_SIMILAR", "similar") + .addSelect("\"esvlistaprodutos\".TIPO_CAMPANHA", "type_campaing") .where("(\"esvlistaprodutos\".codfilial = :codfilial OR :codfilial = '99')", { codfilial: store }) .andWhere("(\"esvlistaprodutos\".produto_com_reducao_preco = :produtoComReducaoPreco OR :produtoComReducaoPreco = 'N')", { produtoComReducaoPreco: (filter.markdown.toString() == 'true') ? 'S' : 'N' }) @@ -568,6 +573,7 @@ export class SalesService { .addSelect("\"esvlistaprodutos\".BASETINTOMETRICO", "base") .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") .addSelect("\"esvlistaprodutos\".TEM_PRODUTO_SIMILAR", "similar") + .addSelect("\"esvlistaprodutos\".TIPO_CAMPANHA", "type_campaing") .where("esvlistaprodutos.idProduct = :id", { id: numbers }) .andWhere("\"esvlistaprodutos\".codfilial = :codfilial OR :codfilial = '99'", { codfilial: store }) .limit(pageSize) @@ -616,6 +622,7 @@ export class SalesService { .addSelect("\"esvlistaprodutos\".BASETINTOMETRICO", "base") .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") .addSelect("\"esvlistaprodutos\".TEM_PRODUTO_SIMILAR", "similar") + .addSelect("\"esvlistaprodutos\".TIPO_CAMPANHA", "type_campaing") .where("esvlistaprodutos.CODAUXILIAR = :id", { id: numbers }) .andWhere("(\"esvlistaprodutos\".codfilial = :codfilial OR :codfilial = '99')", { codfilial: store }) .limit(pageSize) @@ -666,6 +673,7 @@ export class SalesService { .addSelect("\"esvlistaprodutos\".BASETINTOMETRICO", "base") .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") .addSelect("\"esvlistaprodutos\".TEM_PRODUTO_SIMILAR", "similar") + .addSelect("\"esvlistaprodutos\".TIPO_CAMPANHA", "type_campaing") .where("UPPER(esvlistaprodutos.CODFAB) like REPLACE(:description, '@', '%')", { description }) .andWhere("\"esvlistaprodutos\".codfilial = :codfilial OR :codfilial = '99'", { codfilial: store }) .limit(pageSize) @@ -713,6 +721,7 @@ export class SalesService { .addSelect("\"esvlistaprodutos\".BASETINTOMETRICO", "base") .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") .addSelect("\"esvlistaprodutos\".TEM_PRODUTO_SIMILAR", "similar") + .addSelect("\"esvlistaprodutos\".TIPO_CAMPANHA", "type_campaing") .where("UPPER(esvlistaprodutos.DESCRICAO) like REPLACE(:description, '@', '%')", { description }) .andWhere("\"esvlistaprodutos\".codfilial = :codfilial OR :codfilial = '99'", { codfilial: store }) .limit(pageSize) @@ -783,6 +792,7 @@ export class SalesService { .addSelect("\"esvlistaprodutos\".BASETINTOMETRICO", "base") .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") .addSelect("\"esvlistaprodutos\".TEM_PRODUTO_SIMILAR", "similar") + .addSelect("\"esvlistaprodutos\".TIPO_CAMPANHA", "type_campaing") .where("esvlistaprodutos.idProduct = :id", { id: id }) .andWhere("\"esvlistaprodutos\".codfilial = :codfilial", { codfilial: store }) .orderBy("REPLACE(\"esvlistaprodutos\".DESCRICAO,'#', '')", "ASC") @@ -845,6 +855,7 @@ export class SalesService { ,esvlistaprodutos.BASETINTOMETRICO as "base" ,esvlistaprodutos.QUANTIDADE_ESTOQUE_GERAL as "full_stock" ,esvlistaprodutos.TEM_PRODUTO_SIMILAR as "similar" + ,esvlistaprodutos.TIPO_CAMPANHA as "type_campaing" FROM ESVLISTAPRODUTOS, ESTCOMPREJUNTO WHERE ESVLISTAPRODUTOS.CODPROD = ESTCOMPREJUNTO.CODPROD AND ESTCOMPREJUNTO.CODPRODVENDA = ${id} @@ -906,6 +917,7 @@ export class SalesService { ,esvlistaprodutos.BASETINTOMETRICO as "base" ,esvlistaprodutos.QUANTIDADE_ESTOQUE_GERAL as "full_stock" ,esvlistaprodutos.TEM_PRODUTO_SIMILAR as "similar" + ,esvlistaprodutos.TIPO_CAMPANHA as "type_campaing" FROM ESVLISTAPRODUTOS, PCPRODSIMIL WHERE ESVLISTAPRODUTOS.CODPROD = PCPRODSIMIL.CODSIMIL AND PCPRODSIMIL.CODPROD = ${id} @@ -1338,8 +1350,9 @@ export class SalesService { ' ,esvlistaprodutos.LITRAGEM "can" ' + ' ,esvlistaprodutos.QUANTIDADE_ESTOQUE_GERAL "full_stock" ' + ' ,esvlistaprodutos.TEM_PRODUTO_SIMILAR "similar" ' + + ' ,esvlistaprodutos.TIPO_CAMPANHA "type_campaing" ' + ' FROM esvlistaprodutos ' + - ' WHERE 1 = 1'; + ' WHERE 1 = 1 '; let where = ""; if (filter.text != null) { -- 2.49.1 From 395c6de2c68eb0df3a1fd8a91efe0585946491c0 Mon Sep 17 00:00:00 2001 From: simplifique Date: Fri, 2 Jan 2026 18:13:58 -0500 Subject: [PATCH 04/20] first commit --- README.md | 150 +++++++++++++++++++++++++++--------------------------- 1 file changed, 75 insertions(+), 75 deletions(-) diff --git a/README.md b/README.md index a59ef92..9cee7a2 100644 --- a/README.md +++ b/README.md @@ -1,75 +1,75 @@ -

- Nest Logo -

- -[travis-image]: https://api.travis-ci.org/nestjs/nest.svg?branch=master -[travis-url]: https://travis-ci.org/nestjs/nest -[linux-image]: https://img.shields.io/travis/nestjs/nest/master.svg?label=linux -[linux-url]: https://travis-ci.org/nestjs/nest - -

A progressive Node.js framework for building efficient and scalable server-side applications, heavily inspired by Angular.

-

-NPM Version -Package License -NPM Downloads -Travis -Linux -Coverage -Gitter -Backers on Open Collective -Sponsors on Open Collective - - -

- - -## Description - -[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository. - -## Installation - -```bash -$ npm install -``` - -## Running the app - -```bash -# development -$ npm run start - -# watch mode -$ npm run start:dev - -# production mode -$ npm run start:prod -``` - -## Test - -```bash -# unit tests -$ npm run test - -# e2e tests -$ npm run test:e2e - -# test coverage -$ npm run test:cov -``` - -## Support - -Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support). - -## Stay in touch - -- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com) -- Website - [https://nestjs.com](https://nestjs.com/) -- Twitter - [@nestframework](https://twitter.com/nestframework) - -## License - - Nest is [MIT licensed](LICENSE). +

+ Nest Logo +

+ +[travis-image]: https://api.travis-ci.org/nestjs/nest.svg?branch=master +[travis-url]: https://travis-ci.org/nestjs/nest +[linux-image]: https://img.shields.io/travis/nestjs/nest/master.svg?label=linux +[linux-url]: https://travis-ci.org/nestjs/nest + +

A progressive Node.js framework for building efficient and scalable server-side applications, heavily inspired by Angular.

+

+NPM Version +Package License +NPM Downloads +Travis +Linux +Coverage +Gitter +Backers on Open Collective +Sponsors on Open Collective + + +

+ + +## Description + +[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository. + +## Installation + +```bash +$ npm install +``` + +## Running the app + +```bash +# development +$ npm run start + +# watch mode +$ npm run start:dev + +# production mode +$ npm run start:prod +``` + +## Test + +```bash +# unit tests +$ npm run test + +# e2e tests +$ npm run test:e2e + +# test coverage +$ npm run test:cov +``` + +## Support + +Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support). + +## Stay in touch + +- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com) +- Website - [https://nestjs.com](https://nestjs.com/) +- Twitter - [@nestframework](https://twitter.com/nestframework) + +## License + + Nest is [MIT licensed](LICENSE). -- 2.49.1 From 7a9a40e8595545661c54cd6e6c55850efcba3437 Mon Sep 17 00:00:00 2001 From: simplifique Date: Fri, 2 Jan 2026 18:31:38 -0500 Subject: [PATCH 05/20] first --- .env | 8 ++++++ .gitea/workflows/deploy-api.yaml | 28 +++++++++++++++++++ .gitea/workflows/rollback.md | 7 +++++ Dockerfile | 46 +++++++++++++++++++------------- docker-compose.yml | 22 ++++++++------- src/configs/typeorm.config.ts | 24 +++++++++-------- 6 files changed, 96 insertions(+), 39 deletions(-) create mode 100644 .env create mode 100644 .gitea/workflows/deploy-api.yaml create mode 100644 .gitea/workflows/rollback.md diff --git a/.env b/.env new file mode 100644 index 0000000..461822b --- /dev/null +++ b/.env @@ -0,0 +1,8 @@ +ORACLE_CLIENT_PATH='/usr/lib/oracle/21/client64/lib' + + +####ORACLE +PORT='8065' +DB_USERNAME='simplifique' +DB_PASSWORD='simplifique' +DB_CONNECT_STRING='(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=172.35.0.250)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCL)))' diff --git a/.gitea/workflows/deploy-api.yaml b/.gitea/workflows/deploy-api.yaml new file mode 100644 index 0000000..68a53b7 --- /dev/null +++ b/.gitea/workflows/deploy-api.yaml @@ -0,0 +1,28 @@ +name: Deploy NestJS API +on: [push] + +jobs: + build-and-push-deploy: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Login no Harbor + run: | + echo "${{ secrets.HARBOR_PASSWORD }}" | docker login 172.35.0.216 -u ${{ secrets.HARBOR_USERNAME }} --password-stdin + + - name: Build e Push + run: | + # Usando o SHA do commit para manter o histórico no Harbor + TAG=${{ gitea.sha }} + docker build -t 172.35.0.216/library/vendaweb-api:$TAG . + docker tag 172.35.0.216/library/vendaweb-api:$TAG 172.35.0.216/library/vendaweb-api:latest + + docker push 172.35.0.216/library/vendaweb-api:$TAG + docker push 172.35.0.216/library/vendaweb-api:latest + + - name: Notificar Portainer via Webhook + run: | + # O Webhook avisa o Portainer para puxar a nova imagem imediatamente + curl -X POST "${{ secrets.PORTAINER_WEBHOOK_URL }}" \ No newline at end of file diff --git a/.gitea/workflows/rollback.md b/.gitea/workflows/rollback.md new file mode 100644 index 0000000..74f0df8 --- /dev/null +++ b/.gitea/workflows/rollback.md @@ -0,0 +1,7 @@ +O Rollback via Git (Mais Seguro) + +No Gitea, faça um git revert no commit que deu erro. + +Dê o git push. + +O Portainer detectará a mudança e atualizará o serviço para a versão estável de forma oficial. \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 8212c4d..59bc96b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,32 +1,40 @@ -FROM node:16 +# Estágio 1: Build +FROM node:16-slim AS builder +WORKDIR /app +COPY package*.json ./ +RUN npm install --legacy-peer-deps +COPY . . +RUN npm run build +FROM node:16-slim + +# Instalar dependências do Oracle RUN apt-get update && apt-get install -y \ - apt-transport-https \ - ca-certificates \ libaio1 \ unzip \ wget \ - libc6 \ - libncurses5 && \ - mkdir -p /opt/oracle && \ - wget https://download.oracle.com/otn_software/linux/instantclient/instantclient-basic-linuxx64.zip -O /opt/oracle/instantclient-basic-linuxx64.zip && \ - unzip /opt/oracle/instantclient-basic-linuxx64.zip -d /opt/oracle && \ - rm /opt/oracle/instantclient-basic-linuxx64.zip && \ - ln -s /opt/oracle/instantclient_* /opt/oracle/instantclient && \ - echo "/opt/oracle/instantclient" > /etc/ld.so.conf.d/oracle-instantclient.conf && \ - ldconfig + && mkdir -p /opt/oracle +# Instalar Oracle Instant Client +RUN wget https://download.oracle.com/otn_software/linux/instantclient/instantclient-basic-linuxx64.zip -O /opt/oracle/client.zip && \ + unzip /opt/oracle/client.zip -d /opt/oracle && \ + rm /opt/oracle/client.zip && \ + ln -s /opt/oracle/instantclient_* /opt/oracle/instantclient + +# Configurar o sistema para encontrar as bibliotecas do Oracle +ENV LD_LIBRARY_PATH=/opt/oracle/instantclient +RUN echo "/opt/oracle/instantclient" > /etc/ld.so.conf.d/oracle-instantclient.conf && ldconfig WORKDIR /app +# Copiar apenas o necessário do estágio anterior +COPY --from=builder /app/dist ./dist +COPY --from=builder /app/package*.json ./ +COPY --from=builder /app/node_modules ./node_modules -COPY package*.json ./ - - -RUN npm install --legacy-peer-deps - -COPY . . - +# Variáveis de ambiente padrão para o driver oracledb +ENV OCI_LIB_DIR=/opt/oracle/instantclient +ENV OCI_INC_DIR=/opt/oracle/instantclient/sdk/include CMD ["npm", "run", "start:prod"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 6aa3eac..661cdbb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,14 +1,18 @@ version: '3.8' services: - vendaweb: - image: link70/vendaweb - deploy: - replicas: 20 - resources: - limits: - cpus: '0.5' - memory: 512M + vendaweb-api: + image: 172.35.0.216/library/vendaweb-api:latest ports: - "8065:8065" - restart: always \ No newline at end of file + networks: + - simplifique-network + deploy: + replicas: 4 + update_config: + order: start-first + parallelism: 1 + +networks: + simplifique-network: + external: true \ No newline at end of file diff --git a/src/configs/typeorm.config.ts b/src/configs/typeorm.config.ts index 3b30a6b..0862157 100644 --- a/src/configs/typeorm.config.ts +++ b/src/configs/typeorm.config.ts @@ -1,18 +1,17 @@ import { TypeOrmModuleOptions } from '@nestjs/typeorm'; import { ConnectionOptions } from 'typeorm'; +import 'dotenv/config'; export const typeOrmConfig: TypeOrmModuleOptions = { type: "oracle", - // host: "192.168.100.40", - // username: "LIVIA", - // password: "LIVIA", host: "10.1.1.241", - username: "SEVEN", - password: "USR54SEV", - // username: "API", - // password: "E05H5KIEQV3YKDJR", + username: process.env.DB_USERNAME || "simplifique", + password: process.env.DB_PASSWORD || "simplifique", + connectString: + process.env.DB_CONNECT_STRING || + '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=172.35.0.250)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCL)))', port: 1521, - sid: "WINT", + sid: "ORCL", synchronize: false, logging: false, entities: [__dirname + '/../**/*.entity.{js,ts}'], @@ -22,10 +21,13 @@ export const typeOrmConfig: TypeOrmModuleOptions = { export const connectionOptions: ConnectionOptions = { type: "oracle", host: "10.1.1.241", - username: "SEVEN", - password: "USR54SEV", + username: process.env.DB_USERNAME || "simplifique", + password: process.env.DB_PASSWORD || "simplifique", + connectString: + process.env.DB_CONNECT_STRING || + '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=172.35.0.250)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCL)))', port: 1521, - sid: "WINT", + sid: "ORCL", synchronize: false, logging: false, entities: [__dirname + '/../**/*.entity.{js,ts}'], -- 2.49.1 From dfd6c0ef8a86d9e404669ee7bfafd5be750e47c0 Mon Sep 17 00:00:00 2001 From: simplifique Date: Fri, 2 Jan 2026 18:37:24 -0500 Subject: [PATCH 06/20] first --- .gitea/workflows/deploy-api.yaml | 2 +- Dockerfile | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/deploy-api.yaml b/.gitea/workflows/deploy-api.yaml index 68a53b7..5de6b64 100644 --- a/.gitea/workflows/deploy-api.yaml +++ b/.gitea/workflows/deploy-api.yaml @@ -25,4 +25,4 @@ jobs: - name: Notificar Portainer via Webhook run: | # O Webhook avisa o Portainer para puxar a nova imagem imediatamente - curl -X POST "${{ secrets.PORTAINER_WEBHOOK_URL }}" \ No newline at end of file + curl -X POST "${{ secrets.PORTAINER_WEBHOOK_VENDAWEBAPI }}" \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 59bc96b..666cad4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Estágio 1: Build -FROM node:16-slim AS builder +FROM node:16 WORKDIR /app COPY package*.json ./ @@ -7,7 +7,7 @@ RUN npm install --legacy-peer-deps COPY . . RUN npm run build -FROM node:16-slim +FROM node:16 # Instalar dependências do Oracle RUN apt-get update && apt-get install -y \ -- 2.49.1 From e1159acdf0069daf41d4cc4d3af8fe26540ed0c4 Mon Sep 17 00:00:00 2001 From: simplifique Date: Fri, 2 Jan 2026 18:38:52 -0500 Subject: [PATCH 07/20] :ok --- Dockerfile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 666cad4..b06031e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Estágio 1: Build -FROM node:16 +FROM node:16-bullseye-slim AS builder WORKDIR /app COPY package*.json ./ @@ -7,8 +7,7 @@ RUN npm install --legacy-peer-deps COPY . . RUN npm run build -FROM node:16 - +FROM node:16-bullseye-slim # Instalar dependências do Oracle RUN apt-get update && apt-get install -y \ libaio1 \ -- 2.49.1 From d400a3febbc04614463d4c694f82b1f1c68c0630 Mon Sep 17 00:00:00 2001 From: simplifique Date: Fri, 2 Jan 2026 19:03:18 -0500 Subject: [PATCH 08/20] =?UTF-8?q?:ok=20configura=C3=A7=C3=A3o=20das=20vari?= =?UTF-8?q?aveis=20do=20redis?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/redis/redis.providers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/redis/redis.providers.ts b/src/redis/redis.providers.ts index e32e868..74868e7 100644 --- a/src/redis/redis.providers.ts +++ b/src/redis/redis.providers.ts @@ -5,7 +5,7 @@ export const redisProvider: Provider = { provide: 'REDIS_CLIENT', useFactory: () => { return new Redis({ - host: '10.1.1.109', + host: '172.35.0.217', port: 6379, }); }, -- 2.49.1 From 699a9191e27dccc78c56be51d5b183773bd40f61 Mon Sep 17 00:00:00 2001 From: simplifique Date: Fri, 2 Jan 2026 19:23:49 -0500 Subject: [PATCH 09/20] feat: configure Redis connection and update server port --- .env | 5 +++++ src/main.ts | 2 +- src/redis/redis.providers.ts | 7 +++++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.env b/.env index 461822b..93f450a 100644 --- a/.env +++ b/.env @@ -1,6 +1,11 @@ ORACLE_CLIENT_PATH='/usr/lib/oracle/21/client64/lib' +###REDIS +REDIS_HOST='172.35.0.217' +REDIS_PORT='6379' + + ####ORACLE PORT='8065' DB_USERNAME='simplifique' diff --git a/src/main.ts b/src/main.ts index 169cb70..f6e85dc 100644 --- a/src/main.ts +++ b/src/main.ts @@ -20,6 +20,6 @@ async function bootstrap() { .build(); const document = SwaggerModule.createDocument(app, options); SwaggerModule.setup("docs", app, document); - await app.listen(8065); + await app.listen(8067); } bootstrap(); diff --git a/src/redis/redis.providers.ts b/src/redis/redis.providers.ts index 74868e7..6668b3c 100644 --- a/src/redis/redis.providers.ts +++ b/src/redis/redis.providers.ts @@ -1,12 +1,15 @@ import { Provider } from '@nestjs/common'; import Redis = require('ioredis'); +import 'dotenv/config'; + + export const redisProvider: Provider = { provide: 'REDIS_CLIENT', useFactory: () => { return new Redis({ - host: '172.35.0.217', - port: 6379, + host: process.env.REDIS_HOST, + port: parseInt(process.env.REDIS_PORT), }); }, }; -- 2.49.1 From f9ba12c43f4c4490ad10a7d552729f5d6012010e Mon Sep 17 00:00:00 2001 From: simplifique Date: Fri, 2 Jan 2026 19:37:51 -0500 Subject: [PATCH 10/20] fix: update Redis connection details to use hardcoded values --- src/redis/redis.providers.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/redis/redis.providers.ts b/src/redis/redis.providers.ts index 6668b3c..0b5e372 100644 --- a/src/redis/redis.providers.ts +++ b/src/redis/redis.providers.ts @@ -1,15 +1,23 @@ import { Provider } from '@nestjs/common'; + import Redis = require('ioredis'); -import 'dotenv/config'; export const redisProvider: Provider = { + provide: 'REDIS_CLIENT', + useFactory: () => { + return new Redis({ - host: process.env.REDIS_HOST, - port: parseInt(process.env.REDIS_PORT), + + host: '172.35.0.217', + + port: 6379, + }); + }, -}; + +}; \ No newline at end of file -- 2.49.1 From 2ff13691b0a9fd7c01ec007ef91c16415524d93d Mon Sep 17 00:00:00 2001 From: simplifique Date: Fri, 2 Jan 2026 19:38:20 -0500 Subject: [PATCH 11/20] fix: update server port from 8067 to 8065 --- src/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.ts b/src/main.ts index f6e85dc..169cb70 100644 --- a/src/main.ts +++ b/src/main.ts @@ -20,6 +20,6 @@ async function bootstrap() { .build(); const document = SwaggerModule.createDocument(app, options); SwaggerModule.setup("docs", app, document); - await app.listen(8067); + await app.listen(8065); } bootstrap(); -- 2.49.1 From a3021a545cb9eccf5d2653e5bea9e854f2fe9397 Mon Sep 17 00:00:00 2001 From: simplifique Date: Mon, 5 Jan 2026 18:35:07 -0500 Subject: [PATCH 12/20] fix: update health check response to include versioning --- .gitea/workflows/deploy-api.yaml | 1 - .gitignore | 3 +++ src/app.controller.ts | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/deploy-api.yaml b/.gitea/workflows/deploy-api.yaml index 5de6b64..04c29a7 100644 --- a/.gitea/workflows/deploy-api.yaml +++ b/.gitea/workflows/deploy-api.yaml @@ -14,7 +14,6 @@ jobs: - name: Build e Push run: | - # Usando o SHA do commit para manter o histórico no Harbor TAG=${{ gitea.sha }} docker build -t 172.35.0.216/library/vendaweb-api:$TAG . docker tag 172.35.0.216/library/vendaweb-api:$TAG 172.35.0.216/library/vendaweb-api:latest diff --git a/.gitignore b/.gitignore index 62da189..24123c3 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,6 @@ lerna-debug.log* !.vscode/launch.json !.vscode/extensions.json +# Environment variables +.env + diff --git a/src/app.controller.ts b/src/app.controller.ts index 470a286..7f421c6 100644 --- a/src/app.controller.ts +++ b/src/app.controller.ts @@ -14,7 +14,7 @@ export class AppController { @Get('health') @ApiOperation({ summary: 'Health check' }) healthCheck() { - return { status: 'ok' }; + return { status: 'ok v2' }; } } -- 2.49.1 From e2a008e9a9fdfbc7fa9e50254cc49891dc15caab Mon Sep 17 00:00:00 2001 From: simplifique Date: Mon, 5 Jan 2026 18:45:48 -0500 Subject: [PATCH 13/20] fix: update health check response to return version 3 --- src/app.controller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app.controller.ts b/src/app.controller.ts index 7f421c6..18fffae 100644 --- a/src/app.controller.ts +++ b/src/app.controller.ts @@ -14,7 +14,7 @@ export class AppController { @Get('health') @ApiOperation({ summary: 'Health check' }) healthCheck() { - return { status: 'ok v2' }; + return { status: 'ok v3' }; } } -- 2.49.1 From 91f3e857a041cd2140a348341d7729d0c9b4b843 Mon Sep 17 00:00:00 2001 From: simplifique Date: Mon, 5 Jan 2026 19:15:40 -0500 Subject: [PATCH 14/20] fix: refactor AppService to ProductsService and implement product management methods --- src/app.controller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app.controller.ts b/src/app.controller.ts index 18fffae..afa0879 100644 --- a/src/app.controller.ts +++ b/src/app.controller.ts @@ -14,7 +14,7 @@ export class AppController { @Get('health') @ApiOperation({ summary: 'Health check' }) healthCheck() { - return { status: 'ok v3' }; + return { status: 'simplifique home center' }; } } -- 2.49.1 From 19d34ea672dd4b5cf2eaa6f9672d87a907237bea Mon Sep 17 00:00:00 2001 From: simplifique Date: Mon, 5 Jan 2026 19:21:22 -0500 Subject: [PATCH 15/20] fix: correct health check response message typo --- src/app.controller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app.controller.ts b/src/app.controller.ts index afa0879..03d02e9 100644 --- a/src/app.controller.ts +++ b/src/app.controller.ts @@ -14,7 +14,7 @@ export class AppController { @Get('health') @ApiOperation({ summary: 'Health check' }) healthCheck() { - return { status: 'simplifique home center' }; + return { status: 'simplifique home centerrr' }; } } -- 2.49.1 From ce988e93b18e70df8eede099be7ba1aec2083161 Mon Sep 17 00:00:00 2001 From: simplifique Date: Mon, 5 Jan 2026 19:30:19 -0500 Subject: [PATCH 16/20] fix: update database host in TypeORM configuration --- src/configs/typeorm.config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/configs/typeorm.config.ts b/src/configs/typeorm.config.ts index 0862157..2bf88a4 100644 --- a/src/configs/typeorm.config.ts +++ b/src/configs/typeorm.config.ts @@ -4,7 +4,7 @@ import 'dotenv/config'; export const typeOrmConfig: TypeOrmModuleOptions = { type: "oracle", - host: "10.1.1.241", + host: "172.35.0.250", username: process.env.DB_USERNAME || "simplifique", password: process.env.DB_PASSWORD || "simplifique", connectString: @@ -20,7 +20,7 @@ export const typeOrmConfig: TypeOrmModuleOptions = { export const connectionOptions: ConnectionOptions = { type: "oracle", - host: "10.1.1.241", + host: "172.35.0.250", username: process.env.DB_USERNAME || "simplifique", password: process.env.DB_PASSWORD || "simplifique", connectString: -- 2.49.1 From bda9f0f13b20003c6eab5e0e19cf1b793494e592 Mon Sep 17 00:00:00 2001 From: simplifique Date: Mon, 5 Jan 2026 20:13:29 -0500 Subject: [PATCH 17/20] fix: correct health check response message --- src/app.controller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app.controller.ts b/src/app.controller.ts index 03d02e9..72518bd 100644 --- a/src/app.controller.ts +++ b/src/app.controller.ts @@ -14,7 +14,7 @@ export class AppController { @Get('health') @ApiOperation({ summary: 'Health check' }) healthCheck() { - return { status: 'simplifique home centerrr' }; + return { status: 'simplifique' }; } } -- 2.49.1 From 90366c21e51d4c8a5b3c0f04e375c500632073d8 Mon Sep 17 00:00:00 2001 From: simplifique Date: Mon, 5 Jan 2026 20:32:26 -0500 Subject: [PATCH 18/20] fix: update health check response status message --- src/app.controller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app.controller.ts b/src/app.controller.ts index 72518bd..7242992 100644 --- a/src/app.controller.ts +++ b/src/app.controller.ts @@ -14,7 +14,7 @@ export class AppController { @Get('health') @ApiOperation({ summary: 'Health check' }) healthCheck() { - return { status: 'simplifique' }; + return { status: 'SIMPLIFIQUE HOME CENTER' }; } } -- 2.49.1 From 2b9868bf6daa5c116d5ad353ffca39f239b5a91b Mon Sep 17 00:00:00 2001 From: Luis Eduardo Estevao Date: Wed, 7 Jan 2026 20:23:23 -0300 Subject: [PATCH 19/20] feat: add app controller with endpoints for application version and health checks. --- src/app.controller.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app.controller.ts b/src/app.controller.ts index 7242992..1902f02 100644 --- a/src/app.controller.ts +++ b/src/app.controller.ts @@ -12,9 +12,9 @@ export class AppController { } @Get('health') -@ApiOperation({ summary: 'Health check' }) -healthCheck() { - return { status: 'SIMPLIFIQUE HOME CENTER' }; -} + @ApiOperation({ summary: 'Health check' }) + healthCheck() { + return { status: 'SIMPLIFIQUE HOME CENTER 2026' }; + } } -- 2.49.1 From 6c1599fbaab816f4e2990a4b596240281df3e822 Mon Sep 17 00:00:00 2001 From: Luis Eduardo Estevao Date: Mon, 12 Jan 2026 16:19:11 -0300 Subject: [PATCH 20/20] Ajustes para simplifique --- src/Auth/services/user.service.ts | 6 +- src/domain/entity/tables/pcclient.entity.ts | 8 +- src/sales/customer/customer.service.ts | 78 ++--- src/sales/sales/sales.service.ts | 330 ++++++++++---------- 4 files changed, 211 insertions(+), 211 deletions(-) diff --git a/src/Auth/services/user.service.ts b/src/Auth/services/user.service.ts index 86584c5..d62aa80 100644 --- a/src/Auth/services/user.service.ts +++ b/src/Auth/services/user.service.ts @@ -93,7 +93,7 @@ export class UserService { ' WHERE PCEMPR.CODFILIAL = PCFILIAL.CODIGO (+)' + ' AND PCPARAMFILIAL.CODFILIAL = \'99\' ' + ' AND PCPARAMFILIAL.NOME = \'CON_CODSETORGERENTELOJA\' ' + - ' AND PCEMPR.EMAIL = :username AND PCEMPR.SENHABD = CRYPT(:password, USUARIOBD)'; + ' AND PCEMPR.USUARIOBD = :username AND PCEMPR.SENHABD = CRYPT(:password, USUARIOBD)'; const users = await queryRunner.manager .query(sql, [user.email, user.password]); @@ -141,8 +141,8 @@ export class UserService { const noDeliveryDays = await queryRunner.manager .query(sqlDiasSemEntrega, [Number.parseInt(users[0].deliveryTime)]); - const days = Number.parseInt(deliveryDays2[0].days) + - ( noDeliveryDays.length > 0 ? Number.parseInt(noDeliveryDays[0].daysNoDelivery) : 0 ); + const days = Number.parseInt(deliveryDays2[0].days) + + (noDeliveryDays.length > 0 ? Number.parseInt(noDeliveryDays[0].daysNoDelivery) : 0); const userDb = users[0]; console.log(userDb); diff --git a/src/domain/entity/tables/pcclient.entity.ts b/src/domain/entity/tables/pcclient.entity.ts index f5570be..5a6cee5 100644 --- a/src/domain/entity/tables/pcclient.entity.ts +++ b/src/domain/entity/tables/pcclient.entity.ts @@ -1355,7 +1355,7 @@ export class Pcclient { @Column({ name: 'ORGAOPUBMUNICIPAL' }) orgaopubmunicipal: string; - @Column({ name: 'CODCIDADECOM' }) + @Column({ name: 'CODCIDADECOM' }) codcidadecom: number; @Column({ name: 'CODPROMOCAOMED' }) @@ -1622,8 +1622,8 @@ export class Pcclient { @Column({ name: 'CODCONDCOMERCIAL' }) codcondcomercial: string; - @Column({ name: 'MEIOCOMUNICACAO' }) - meiocomunicacao: string; + // @Column({ name: 'MEIOCOMUNICACAO' }) + // meiocomunicacao: string; @Column({ name: 'CODGRUPOCOMERCIALMED' }) codgrupocomercialmed: number; @@ -1645,5 +1645,5 @@ export class Pcclient { @OneToMany(() => Pcpedc, pedidos => pedidos.pcclient) pedidos: Pcpedc[]; - + } \ No newline at end of file diff --git a/src/sales/customer/customer.service.ts b/src/sales/customer/customer.service.ts index 60d5f7d..9ffc223 100644 --- a/src/sales/customer/customer.service.ts +++ b/src/sales/customer/customer.service.ts @@ -44,7 +44,7 @@ export class CustomerService { ' ,pccidade.codibge as "ibgeCode" ' + ' ,pcclient.dtnasc as "birthdate" ' + ' ,pcclient.codatv1 as "ramoId" ' + - ' ,pcclient.meiocomunicacao as "communicate" ' + + // ' ,pcclient.meiocomunicacao as "communicate" ' + ' ,pcclient.latitude as "latitude" ' + ' ,pcclient.longitude as "longitude" ' + ' ,pcclient.codmunicipio as "ibgeCode" ' + @@ -102,16 +102,16 @@ export class CustomerService { ' ,pcclient.telent as "phone" ' + ' ,pcclient.telcelent as "cellPhone" ' + ' ,pcclient.ieent as "numberState" ' + - ' ,pcclient.codcategoria as "categoryId" ' + - ' ,pcclient.codsubcategoria as "subCategoryId" ' + + // ' ,pcclient.codcategoria as "categoryId" ' + + // ' ,pcclient.codsubcategoria as "subCategoryId" ' + ' ,pcclient.codpraca as "placeId" ' + ' ,pcclient.codusur1 as "sellerId" ' + ' ,pccidade.codibge as "ibgeCode" ' + ' ,pcclient.dtnasc as "birthdate" ' + ' ,pcclient.codatv1 as "ramoId" ' + - ' ,pcclient.meiocomunicacao as "communicate" ' + + // ' ,pcclient.meiocomunicacao as "communicate" ' + ' ,pcclient.latitude as "latitude" ' + - ' ,pcclient.longitude as "longitude" ' + + ' ,pcclient.longitude as "longitude" ' + ' ,pcclient.codmunicipio as "ibgeCode" ' + ' ,pcclient.codcidade as "cityId" ' + ' ,pcclient.tipoendereco as "addressType" ' + @@ -158,7 +158,7 @@ export class CustomerService { ' ,pccidade.codibge as "ibgeCode" ' + ' ,pcclient.dtnasc as "birthdate" ' + ' ,pcclient.codatv1 as "ramoId" ' + - ' ,pcclient.meiocomunicacao as "communicate" ' + + //' ,pcclient.meiocomunicacao as "communicate" ' + ' ,pcclient.latitude as "latitude" ' + ' ,pcclient.longitude as "longitude" ' + ' ,pcclient.codmunicipio as "ibgeCode" ' + @@ -173,7 +173,7 @@ export class CustomerService { FROM PCPRACA WHERE PCPRACA.CODPRACA = ${customer[0].placeId}`); - return {...customer[0], place: place[0]}; + return { ...customer[0], place: place[0] }; } catch (error) { console.log(error); throw error; @@ -267,16 +267,16 @@ export class CustomerService { newCustomer.telcelent = customer.cellPhone; newCustomer.celularwhatsapp = customer.cellPhone; newCustomer.codusur1 = customer.sellerId; - newCustomer.codatv1 = ( customer.ramo != null && customer.ramo.id > 0 ) ? customer.ramo.id : newCustomer.codatv1; + newCustomer.codatv1 = (customer.ramo != null && customer.ramo.id > 0) ? customer.ramo.id : newCustomer.codatv1; //Endereço de entrega newCustomer.cepent = customer.zipCode; newCustomer.enderent = customer.address.toUpperCase(); newCustomer.numeroent = customer.addressNumber; - if ( customer.complement !== null && customer.complement.length > 80 ) { - newCustomer.complementoent = customer.complement.substring(0, 80 ).toUpperCase(); + if (customer.complement !== null && customer.complement.length > 80) { + newCustomer.complementoent = customer.complement.substring(0, 80).toUpperCase(); } else { - if ( customer.complement != null ) { - newCustomer.complementoent = customer.complement.toUpperCase(); + if (customer.complement != null) { + newCustomer.complementoent = customer.complement.toUpperCase(); } } newCustomer.bairroent = customer.neighborhood.toUpperCase(); @@ -286,10 +286,10 @@ export class CustomerService { newCustomer.cepcom = customer.zipCode; newCustomer.endercom = customer.address.toUpperCase(); newCustomer.numerocom = customer.addressNumber.toUpperCase(); - if ( customer.complement !== null && customer.complement.length > 80 ) { - newCustomer.complementocom = customer.complement.substring(0, 80 ).toUpperCase(); + if (customer.complement !== null && customer.complement.length > 80) { + newCustomer.complementocom = customer.complement.substring(0, 80).toUpperCase(); } else { - if ( customer.complement != null ) { + if (customer.complement != null) { newCustomer.complementocom = customer.complement.toUpperCase(); } } @@ -300,12 +300,12 @@ export class CustomerService { newCustomer.cepcob = customer.zipCode; newCustomer.endercob = customer.address.toUpperCase(); newCustomer.numerocob = customer.addressNumber; - if ( customer.complement !== null && customer.complement.length > 80 ) { - newCustomer.complementocob = customer.complement.substring(0, 80 ).toUpperCase(); + if (customer.complement !== null && customer.complement.length > 80) { + newCustomer.complementocob = customer.complement.substring(0, 80).toUpperCase(); } else { - if ( customer.complement ) { + if (customer.complement) { newCustomer.complementocob = customer.complement.toUpperCase(); - } + } } newCustomer.bairrocob = customer.neighborhood.toUpperCase(); newCustomer.municcob = customer.city.toUpperCase(); @@ -317,7 +317,7 @@ export class CustomerService { newCustomer.codmunicipio = Number.parseInt(customer.ibgeCode); newCustomer.codcidadecom = newCustomer.codcidade; newCustomer.dtnasc = customer.birthdate; - newCustomer.meiocomunicacao = customer.communicate; + // newCustomer.meiocomunicacao = customer.communicate; newCustomer.codfunccad = customer.idUser; newCustomer.codfunccadastro = customer.idUser; newCustomer.codfuncultalter = customer.idUser; @@ -341,7 +341,7 @@ export class CustomerService { city: customer.city, state: customer.state, allowMessage: customer.allowMessage, cellPhone: customer.cellPhone, category: customer.category, subCategory: customer.subCategory, - place: customer.place, ramo: customer.ramo, meiocomunicacao: customer.communicate, + place: customer.place, ramo: customer.ramo, /*meiocomunicacao: customer.communicate,*/ latitude: customer.latitude, longitude: customer.longitude, ibgeCode: customer.ibgeCode, addressType: customer.addressType, }; @@ -361,8 +361,8 @@ export class CustomerService { city: customer.city, state: customer.state, allowMessage: customer.allowMessage, cellPhone: customer.cellPhone, category: customer.category, subCategory: customer.subCategory, - place: customer.place, meiocomunicacao: customer.communicate, - ramo: customer.ramo, latitude: customer.latitude, longitude: customer.longitude, + place: customer.place, /*meiocomunicacao: customer.communicate,*/ + ramo: customer.ramo, latitude: customer.latitude, longitude: customer.longitude, ibgeCode: customer.ibgeCode, addressType: customer.addressType, }; } @@ -378,7 +378,7 @@ export class CustomerService { await queryRunner.connect(); await queryRunner.startTransaction(); try { - console.log("MEIO DE COMUNICACAO: " + client.meiocomunicacao); + //console.log("MEIO DE COMUNICACAO: " + client.meiocomunicacao); await queryRunner.manager .createQueryBuilder() .update(Pcclient) @@ -418,13 +418,13 @@ export class CustomerService { codmunicipio: client.codmunicipio, codcidadecom: client.codcidade, dtnasc: client.dtnasc, - codatv1: client.codatv1, - meiocomunicacao: client.meiocomunicacao, + codatv1: client.codatv1, + // meiocomunicacao: client.meiocomunicacao, codfuncultalter: client.codfuncultalter, - dtultalter: client.dtultalter, + dtultalter: client.dtultalter, latitude: client.latitude, - longitude: client.longitude, - tipoendereco: client.tipoendereco + longitude: client.longitude, + tipoendereco: client.tipoendereco }) .where({ codcli: client.codcli }) .execute(); @@ -434,7 +434,7 @@ export class CustomerService { await queryRunner.rollbackTransaction(); throw err; } finally { - if ( queryRunner.isTransactionActive) { + if (queryRunner.isTransactionActive) { await queryRunner.rollbackTransaction(); } await queryRunner.release(); @@ -532,13 +532,13 @@ export class CustomerService { const connection = new Connection(connectionOptions); const queryRunner = connection.createQueryRunner(); try { - - await connection.connect(); - - await queryRunner.connect(); - // lets now open a new transaction: - await queryRunner.startTransaction(); + await connection.connect(); + + await queryRunner.connect(); + + // lets now open a new transaction: + await queryRunner.startTransaction(); let sql = `SELECT PROXNUMCLI as "proxnumcli" FROM PCCONSUM WHERE 1 = 1 FOR UPDATE`; @@ -566,14 +566,14 @@ export class CustomerService { } catch (err) { // since we have errors let's rollback changes we made - if ( queryRunner.isTransactionActive) { + if (queryRunner.isTransactionActive) { await queryRunner.rollbackTransaction(); } console.log(err); return -1; } finally { - if ( queryRunner.isTransactionActive) { + if (queryRunner.isTransactionActive) { await queryRunner.rollbackTransaction(); } // you need to release query runner which is manually created: @@ -603,7 +603,7 @@ export class CustomerService { console.log(err); throw err; } finally { - if ( queryRunner.isTransactionActive) { + if (queryRunner.isTransactionActive) { await queryRunner.rollbackTransaction(); } await queryRunner.release(); diff --git a/src/sales/sales/sales.service.ts b/src/sales/sales/sales.service.ts index 0022357..7769578 100644 --- a/src/sales/sales/sales.service.ts +++ b/src/sales/sales/sales.service.ts @@ -20,10 +20,10 @@ import Redis = require('ioredis'); @Injectable() export class SalesService { - constructor( - @Inject('REDIS_CLIENT') private readonly redisClient: Redis.Redis, - private readonly customerService: CustomerService - ) {} + constructor( + @Inject('REDIS_CLIENT') private readonly redisClient: Redis.Redis, + private readonly customerService: CustomerService + ) { } async GetProducts2(store: string, pageSize: number, pageNumber: number, filter: FilterProduct = null,) { @@ -86,7 +86,7 @@ export class SalesService { if (filter && filter.text.length > 0) { const description = filter.text.toUpperCase(); console.log('consultando por codigo de fabrica'); - + let products = await queryRunner.manager .getRepository(SalesProduct) .createQueryBuilder('esvlistaprodutos') @@ -367,92 +367,92 @@ export class SalesService { pageSize: number, pageNumber: number, urlDepartment: string - ): Promise { + ): Promise { const cacheKey = - 'searchByDepartment:' + - store + - '_' + - pageSize + - '_' + - pageNumber + - '_' + - urlDepartment; + 'searchByDepartment:' + + store + + '_' + + pageSize + + '_' + + pageNumber + + '_' + + urlDepartment; const lockKey = 'lock:' + cacheKey; const lockTimeout = 30; // lock expira em 30 segundos - + try { - const cachedResult = await this.redisClient.get(cacheKey); - if (cachedResult) { - console.log('Retornando resultado do cache (searchByDepartment)'); - return JSON.parse(cachedResult); - } + const cachedResult = await this.redisClient.get(cacheKey); + if (cachedResult) { + console.log('Retornando resultado do cache (searchByDepartment)'); + return JSON.parse(cachedResult); + } } catch (err) { - console.error('Erro ao acessar o Redis no searchByDepartment:', err?.message || err); + console.error('Erro ao acessar o Redis no searchByDepartment:', err?.message || err); } - + const lockValue = Date.now() + lockTimeout * 1000 + 1; let acquiredLock: string | null = null; try { - acquiredLock = await this.redisClient.set(lockKey, lockValue, 'NX', 'EX', lockTimeout); + acquiredLock = await this.redisClient.set(lockKey, lockValue, 'NX', 'EX', lockTimeout); } catch (err) { - console.error('Erro ao adquirir lock no Redis (searchByDepartment):', err?.message || err); + console.error('Erro ao adquirir lock no Redis (searchByDepartment):', err?.message || err); } - + if (acquiredLock === 'OK') { - const connectionDb = new Connection(connectionOptions); - await connectionDb.connect(); - const queryRunner = connectionDb.createQueryRunner(); - await queryRunner.connect(); - try { - if (pageSize === 0) pageSize = 50; - if (pageNumber === 0) pageNumber = 1; - const offSet = (pageNumber - 1) * pageSize; - - let products = await queryRunner.manager - .getRepository(SalesProduct) - .createQueryBuilder('esvlistaprodutos') - .where('"esvlistaprodutos".urldepartamento = :urlDepartment', { urlDepartment }) - .andWhere('("esvlistaprodutos".codfilial = :codfilial OR :codfilial = \'99\')', { codfilial: store }) - .limit(pageSize) - .offset(offSet) - .orderBy('"esvlistaprodutos".DESCRICAO', 'ASC') - .getMany(); - - products = this.createListImages(products); - + const connectionDb = new Connection(connectionOptions); + await connectionDb.connect(); + const queryRunner = connectionDb.createQueryRunner(); + await queryRunner.connect(); try { - await this.redisClient.set(cacheKey, JSON.stringify(products), 'EX', 3600); - } catch (cacheErr) { - console.error('Erro ao salvar o resultado no cache (searchByDepartment):', cacheErr?.message || cacheErr); + if (pageSize === 0) pageSize = 50; + if (pageNumber === 0) pageNumber = 1; + const offSet = (pageNumber - 1) * pageSize; + + let products = await queryRunner.manager + .getRepository(SalesProduct) + .createQueryBuilder('esvlistaprodutos') + .where('"esvlistaprodutos".urldepartamento = :urlDepartment', { urlDepartment }) + .andWhere('("esvlistaprodutos".codfilial = :codfilial OR :codfilial = \'99\')', { codfilial: store }) + .limit(pageSize) + .offset(offSet) + .orderBy('"esvlistaprodutos".DESCRICAO', 'ASC') + .getMany(); + + products = this.createListImages(products); + + try { + await this.redisClient.set(cacheKey, JSON.stringify(products), 'EX', 3600); + } catch (cacheErr) { + console.error('Erro ao salvar o resultado no cache (searchByDepartment):', cacheErr?.message || cacheErr); + } + + return products; + } catch (error) { + console.error('Erro ao executar a query no searchByDepartment:', error?.message || error); + throw error; + } finally { + await queryRunner.release(); + await connectionDb.close(); + + try { + const currentLockValue = await this.redisClient.get(lockKey); + if (currentLockValue === lockValue.toString()) { + await this.redisClient.del(lockKey); + } + } catch (lockErr) { + console.error('Erro ao liberar o lock do Redis (searchByDepartment):', lockErr?.message || lockErr); + } } - - return products; - } catch (error) { - console.error('Erro ao executar a query no searchByDepartment:', error?.message || error); - throw error; - } finally { - await queryRunner.release(); - await connectionDb.close(); - - try { - const currentLockValue = await this.redisClient.get(lockKey); - if (currentLockValue === lockValue.toString()) { - await this.redisClient.del(lockKey); - } - } catch (lockErr) { - console.error('Erro ao liberar o lock do Redis (searchByDepartment):', lockErr?.message || lockErr); - } - } } else { - console.log('Lock não adquirido (searchByDepartment), aguardando e tentando novamente...'); - await this.sleep(1000); - return this.searchByDepartment(store, pageSize, pageNumber, urlDepartment); + console.log('Lock não adquirido (searchByDepartment), aguardando e tentando novamente...'); + await this.sleep(1000); + return this.searchByDepartment(store, pageSize, pageNumber, urlDepartment); } - } - - - - + } + + + + async searchBySection(store: string, pageSize: number, pageNumber: number, urlDepartment: string, urlSection: string): Promise { const connectionDb = new Connection(connectionOptions); @@ -620,7 +620,7 @@ export class SalesService { .addSelect("\"esvlistaprodutos\".PRODUTO_COM_REDUCAO_PRECO", "downPrice") .addSelect("\"esvlistaprodutos\".PRODUTO_EM_CAMPANHA", "compaing") .addSelect("\"esvlistaprodutos\".BASETINTOMETRICO", "base") - .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") + .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") .addSelect("\"esvlistaprodutos\".TEM_PRODUTO_SIMILAR", "similar") .addSelect("\"esvlistaprodutos\".TIPO_CAMPANHA", "type_campaing") .where("esvlistaprodutos.CODAUXILIAR = :id", { id: numbers }) @@ -671,7 +671,7 @@ export class SalesService { .addSelect("\"esvlistaprodutos\".PRODUTO_COM_REDUCAO_PRECO", "downPrice") .addSelect("\"esvlistaprodutos\".PRODUTO_EM_CAMPANHA", "compaing") .addSelect("\"esvlistaprodutos\".BASETINTOMETRICO", "base") - .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") + .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") .addSelect("\"esvlistaprodutos\".TEM_PRODUTO_SIMILAR", "similar") .addSelect("\"esvlistaprodutos\".TIPO_CAMPANHA", "type_campaing") .where("UPPER(esvlistaprodutos.CODFAB) like REPLACE(:description, '@', '%')", { description }) @@ -719,7 +719,7 @@ export class SalesService { .addSelect("\"esvlistaprodutos\".PRODUTO_COM_REDUCAO_PRECO", "downPrice") .addSelect("\"esvlistaprodutos\".PRODUTO_EM_CAMPANHA", "compaing") .addSelect("\"esvlistaprodutos\".BASETINTOMETRICO", "base") - .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") + .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") .addSelect("\"esvlistaprodutos\".TEM_PRODUTO_SIMILAR", "similar") .addSelect("\"esvlistaprodutos\".TIPO_CAMPANHA", "type_campaing") .where("UPPER(esvlistaprodutos.DESCRICAO) like REPLACE(:description, '@', '%')", { description }) @@ -790,7 +790,7 @@ export class SalesService { .addSelect("\"esvlistaprodutos\".PRODUTO_COM_REDUCAO_PRECO", "downPrice") .addSelect("\"esvlistaprodutos\".PRODUTO_EM_CAMPANHA", "compaing") .addSelect("\"esvlistaprodutos\".BASETINTOMETRICO", "base") - .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") + .addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock") .addSelect("\"esvlistaprodutos\".TEM_PRODUTO_SIMILAR", "similar") .addSelect("\"esvlistaprodutos\".TIPO_CAMPANHA", "type_campaing") .where("esvlistaprodutos.idProduct = :id", { id: id }) @@ -958,9 +958,9 @@ export class SalesService { WHERE ESVESTOQUEVENDA.CODPROD = ${id} AND ESVESTOQUEVENDA.CODFILIAL = PCFILIAL.CODIGO ORDER BY TO_NUMBER(ESVESTOQUEVENDA.CODFILIAL) `; - - const stock = await queryRunner.query(sql); - + + const stock = await queryRunner.query(sql); + // return await queryRunner.manager // .getRepository(Stock) // .createQueryBuilder('esvestoquevenda') @@ -1210,71 +1210,71 @@ export class SalesService { const cacheKey = 'departments'; const lockKey = 'departments_lock'; const lockTimeout = 30; - - try { - const cachedDepartments = await this.redisClient.get(cacheKey); - if (cachedDepartments) { - console.log('Buscando departamentos no Redis'); - return JSON.parse(cachedDepartments); - } - } catch (err) { - console.error('Erro ao acessar o Redis (cache):', err); - } - const lockValue = Date.now() + lockTimeout * 1000 + 1; + + // try { + // const cachedDepartments = await this.redisClient.get(cacheKey); + // if (cachedDepartments) { + // console.log('Buscando departamentos no Redis'); + // return JSON.parse(cachedDepartments); + // } + // } catch (err) { + // console.error('Erro ao acessar o Redis (cache):', err); + // } + const lockValue = Date.now() + lockTimeout * 1000 + 1; const acquiredLock = await this.redisClient.set(lockKey, lockValue, 'NX', 'EX', lockTimeout); - + if (acquiredLock === 'OK') { - const connectionDb = new Connection(connectionOptions); - await connectionDb.connect(); - const queryRunner = connectionDb.createQueryRunner(); - await queryRunner.connect(); - - try { - const departments = await queryRunner.manager - .getRepository(Esvdepartamento) - .createQueryBuilder('Esvdepartamento') - .innerJoinAndSelect('Esvdepartamento.secoes', 'secoes') - .innerJoinAndSelect('secoes.categorias', 'categorias') - .where('"Esvdepartamento".tituloecommerce is not null') - .orderBy('"Esvdepartamento".tituloecommerce, "secoes".tituloecommerce, "categorias".tituloecommerce') - .getMany(); - + const connectionDb = new Connection(connectionOptions); + await connectionDb.connect(); + const queryRunner = connectionDb.createQueryRunner(); + await queryRunner.connect(); + try { - await this.redisClient.set(cacheKey, JSON.stringify(departments), 'EX', 3600); - } catch (cacheErr) { - console.error('Erro ao armazenar dados no Redis:', cacheErr); + const departments = await queryRunner.manager + .getRepository(Esvdepartamento) + .createQueryBuilder('Esvdepartamento') + .innerJoinAndSelect('Esvdepartamento.secoes', 'secoes') + .leftJoinAndSelect('secoes.categorias', 'categorias') + .where('"Esvdepartamento".tituloecommerce is not null') + .orderBy('"Esvdepartamento".tituloecommerce, "secoes".tituloecommerce, "categorias".tituloecommerce') + .getMany(); + + try { + await this.redisClient.set(cacheKey, JSON.stringify(departments), 'EX', 3600); + } catch (cacheErr) { + console.error('Erro ao armazenar dados no Redis:', cacheErr); + } + + return departments; + } catch (dbErr) { + console.error('Erro na consulta ao banco de dados:', dbErr); + throw dbErr; + } finally { + await queryRunner.release(); + await connectionDb.close(); + + // Libera o lock somente se ainda for o proprietário + try { + const currentLockValue = await this.redisClient.get(lockKey); + if (currentLockValue === lockValue.toString()) { + await this.redisClient.del(lockKey); + } + } catch (lockErr) { + console.error('Erro ao liberar o lock do Redis:', lockErr); + } } - - return departments; - } catch (dbErr) { - console.error('Erro na consulta ao banco de dados:', dbErr); - throw dbErr; - } finally { - await queryRunner.release(); - await connectionDb.close(); - - // Libera o lock somente se ainda for o proprietário - try { - const currentLockValue = await this.redisClient.get(lockKey); - if (currentLockValue === lockValue.toString()) { - await this.redisClient.del(lockKey); - } - } catch (lockErr) { - console.error('Erro ao liberar o lock do Redis:', lockErr); - } - } } else { - console.log('Lock não adquirido, aguardando a liberação...'); - await this.sleep(1000); // aguarda 1 segundo - return this.getDepartments(); + console.log('Lock não adquirido, aguardando a liberação...'); + await this.sleep(1000); // aguarda 1 segundo + return this.getDepartments(); } - } - private sleep(ms: number): Promise { + } + private sleep(ms: number): Promise { return new Promise(resolve => setTimeout(resolve, ms)); - } - - - + } + + + async getCategory() { @@ -1301,15 +1301,15 @@ export class SalesService { async searchProduct2(store: string, pageSize: number, pageNumber: number, filter: FilterProduct) { console.log('searchProduct2'); - + const cacheKey = `searchProduct2:${store}:${pageSize}:${pageNumber}:${JSON.stringify(filter)}`; - + const cachedProducts = await this.redisClient.get(cacheKey); if (cachedProducts) { console.log('Retornando produtos do cache'); return JSON.parse(cachedProducts); } - + const sql = 'SELECT esvlistaprodutos.CODPROD "idProduct" ' + ` ,esvlistaprodutos.SEQ "seq" ` + ' ,esvlistaprodutos.DESCRICAO "smallDescription" ' + @@ -1352,8 +1352,8 @@ export class SalesService { ' ,esvlistaprodutos.TEM_PRODUTO_SIMILAR "similar" ' + ' ,esvlistaprodutos.TIPO_CAMPANHA "type_campaing" ' + ' FROM esvlistaprodutos ' + - ' WHERE 1 = 1 '; - + ' WHERE 1 = 1 '; + let where = ""; if (filter.text != null) { where += ` AND ( ESF_REMOVE_ACENTUACAO(UPPER(esvlistaprodutos.descricao)) LIKE ` + @@ -1373,7 +1373,7 @@ export class SalesService { where += ` AND (esvlistaprodutos.produto_em_campanha = '${(filter.offers ? 'D' : 'N')}' OR '${(filter.offers ? 'S' : 'N')}' = 'N') `; where += ` AND (esvlistaprodutos.produto_em_campanha = '${(filter.oportunity ? 'O' : 'N')}' OR '${(filter.oportunity ? 'O' : 'N')}' = 'N') `; where += ` AND (esvlistaprodutos.produto_em_promocao = '${(filter.promotion ? 'S' : 'N')}' OR '${(filter.promotion ? 'S' : 'N')}' = 'N') `; - + if (filter.onlyWithStock) { if (filter.storeStock == '' || filter.storeStock == null) { where += ` AND EXISTS( SELECT P.CODPROD FROM ESVLISTAPRODUTOS P ` + @@ -1385,15 +1385,15 @@ export class SalesService { ` AND P.ESTOQUE_DISP_LOJA > 0 ) `; } } - + if (filter.percentOffMin > 0) { where += ` AND esvlistaprodutos.PERCENTUALDESCONTO >= ${filter.percentOffMin}`; } - + if (filter.percentOffMax > 0) { where += ` AND esvlistaprodutos.PERCENTUALDESCONTO <= ${filter.percentOffMax}`; } - + let xbrands = ''; if (filter && filter.brands && filter.brands.length > 0) { const brands = filter.brands; @@ -1406,24 +1406,24 @@ export class SalesService { }); where += ` AND esvlistaprodutos.nomemarca in ( ${xbrands} )`; } - + const orderBy = `ORDER BY esvlistaprodutos.${(filter.orderBy == null) ? 'DESCRICAO' : filter.orderBy}`; - + const skipReg = ((pageNumber - 1) * pageSize); const pagination = ` OFFSET ${skipReg} ROWS FETCH NEXT ${pageSize} ROWS ONLY`; - + const connectionDb = new Connection(connectionOptions); await connectionDb.connect(); const queryRunner = connectionDb.createQueryRunner(); await queryRunner.connect(); - + try { let products = await queryRunner.manager.query(sql + where + orderBy + pagination) as SalesProduct[]; products = this.createListImages(products); console.log("Total de produtos: " + products.length); - + await this.redisClient.set(cacheKey, JSON.stringify(products), 'EX', 3600); - + return products; } catch (err) { console.log(err); @@ -1433,7 +1433,7 @@ export class SalesService { await connectionDb.close(); } } - + async calculateDeliveryTax(cartId: string, ibgeCode: string) { @@ -1488,7 +1488,7 @@ export class SalesService { WHERE ID = '${cartId}'`; await queryRunner.manager - .query(sql); + .query(sql); await queryRunner.commitTransaction(); } catch (err) { await queryRunner.rollbackTransaction(); @@ -1543,26 +1543,26 @@ export class SalesService { await queryRunner.release(); await connectionDb.close(); } - + } - + async getPlacesInterior() { const connectionDb = new Connection(connectionOptions); await connectionDb.connect(); const queryRunner = connectionDb.createQueryRunner(); await queryRunner.connect(); - + try { const sql = ` SELECT DISTINCT ESTPREVENTREGAPRACA.CODPRACA, PCPRACA.PRACA FROM ESTPREVENTREGAPRACA, PCPRACA WHERE ESTPREVENTREGAPRACA.CODPRACA = PCPRACA.CODPRACA `; - + const places = await queryRunner.query(sql); - - + + return places; } catch (err) { throw err; @@ -1571,7 +1571,7 @@ export class SalesService { await connectionDb.close(); } } - + async getDeliveryTime(saleDate: string, invoiceStoreId: string, placeId: string, cartId: string) { const connection = new Connection(connectionOptions); @@ -1580,7 +1580,7 @@ export class SalesService { await queryRunner.connect(); try { const sql = `SELECT ESF_CALCULAR_PRAZO_ENTREGA_PROGRAMADA(TO_DATE('${saleDate}', 'DD-MM-YYYY'), ${invoiceStoreId}, ${placeId}, '${cartId}') AS "days" FROM DUAL`; - // const sql = `SELECT ESF_CALCULAR_PRAZO_ENTREGA(TO_DATE('${saleDate}', 'DD-MM-YYYY')) AS "days" FROM DUAL`; + // const sql = `SELECT ESF_CALCULAR_PRAZO_ENTREGA(TO_DATE('${saleDate}', 'DD-MM-YYYY')) AS "days" FROM DUAL`; const timeDays = await queryRunner.query(sql); const sqlRetiraPosterior = `SELECT ( PROXIMO_DIA_UTIL(TO_DATE('${saleDate}', 'DD-MM-YYYY'), '4') - TRUNC(SYSDATE) ) AS "days" FROM DUAL`; -- 2.49.1