From 054cc2f3bb84c182e0f4a86287af807b0d0b261e Mon Sep 17 00:00:00 2001 From: joelson brito Date: Mon, 10 Nov 2025 12:39:31 -0300 Subject: [PATCH] =?UTF-8?q?Atualiza=C3=A7=C3=B5es=20em=20data-consult=20e?= =?UTF-8?q?=20products?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/data-consult/data-consult.controller.ts | 14 + src/data-consult/data-consult.repository.ts | 11 + src/data-consult/data-consult.service.ts | 17 + src/products/dto/product-detail-query.dto.ts | 15 +- src/products/dto/rotina-a4-query.dto.ts | 14 +- src/products/dto/rotina-a4-response.dto.ts | 6 + src/products/products.controller.ts | 8 +- src/products/products.service.ts | 461 +++++++++++++------ 8 files changed, 396 insertions(+), 150 deletions(-) diff --git a/src/data-consult/data-consult.controller.ts b/src/data-consult/data-consult.controller.ts index 9ea9ed5..c9d1487 100644 --- a/src/data-consult/data-consult.controller.ts +++ b/src/data-consult/data-consult.controller.ts @@ -83,6 +83,20 @@ export class DataConsultController { return this.dataConsultService.customers(filter); } + @UseGuards(JwtAuthGuard) + @ApiBearerAuth() + @Get('products/codauxiliar/:codauxiliar') + @ApiOperation({ summary: 'Busca produtos por código auxiliar (EAN)' }) + @ApiParam({ name: 'codauxiliar', description: 'Código auxiliar (EAN) do produto' }) + @ApiResponse({ + status: 200, + description: 'Lista de produtos encontrados por código auxiliar', + type: [ProductDto], + }) + async productsByCodauxiliar(@Param('codauxiliar') codauxiliar: string): Promise { + return this.dataConsultService.productsByCodauxiliar(codauxiliar); + } + @UseGuards(JwtAuthGuard) @ApiBearerAuth() @Get('products/:filter') diff --git a/src/data-consult/data-consult.repository.ts b/src/data-consult/data-consult.repository.ts index ca5e469..823b265 100644 --- a/src/data-consult/data-consult.repository.ts +++ b/src/data-consult/data-consult.repository.ts @@ -126,6 +126,17 @@ export class DataConsultRepository { return results.map((result) => new ProductDto(result)); } + async findProductsByCodauxiliar(codauxiliar: string): Promise { + const sql = ` + SELECT PCPRODUT.CODPROD as "id", + PCPRODUT.CODPROD || ' - ' || PCPRODUT.DESCRICAO || ' ( ' || PCPRODUT.CODFAB || ' )' as "description" + FROM PCPRODUT + WHERE REGEXP_REPLACE(PCPRODUT.CODAUXILIAR, '[^0-9]', '') = REGEXP_REPLACE(:codauxiliar, '[^0-9]', '') + `; + const results = await this.dataSource.query(sql, [codauxiliar]); + return results.map((result) => new ProductDto(result)); + } + async findAllProducts(): Promise { const sql = ` SELECT PCPRODUT.CODPROD as "id", diff --git a/src/data-consult/data-consult.service.ts b/src/data-consult/data-consult.service.ts index bc08bd5..12d609b 100644 --- a/src/data-consult/data-consult.service.ts +++ b/src/data-consult/data-consult.service.ts @@ -227,6 +227,23 @@ export class DataConsultService { } } + async productsByCodauxiliar(codauxiliar: string): Promise { + this.logger.log(`Buscando produtos por codauxiliar: ${codauxiliar}`); + try { + if (!codauxiliar || typeof codauxiliar !== 'string') { + throw new HttpException('Código auxiliar inválido', HttpStatus.BAD_REQUEST); + } + const products = await this.repository.findProductsByCodauxiliar(codauxiliar); + return products.map((product) => new ProductDto(product)); + } catch (error) { + this.logger.error('Erro ao buscar produtos por codauxiliar', error); + throw new HttpException( + 'Erro ao buscar produtos por codauxiliar', + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + } + async getAllProducts(): Promise { this.logger.log('Buscando todos os produtos'); try { diff --git a/src/products/dto/product-detail-query.dto.ts b/src/products/dto/product-detail-query.dto.ts index 9f2702d..775afa1 100644 --- a/src/products/dto/product-detail-query.dto.ts +++ b/src/products/dto/product-detail-query.dto.ts @@ -14,13 +14,22 @@ export class ProductDetailQueryDto { numregiao: number; @ApiProperty({ - description: 'Array de códigos de produtos', + description: 'Array de códigos de produtos (opcional se codauxiliar for informado)', example: [1, 2, 3], type: [Number], + required: false, }) @IsArray() - @IsNotEmpty() - codprod: number[]; + codprod?: number[]; + + @ApiProperty({ + description: 'Array de códigos auxiliares (opcional se codprod for informado)', + example: ['7891234567890', '7891234567891'], + type: [String], + required: false, + }) + @IsArray() + codauxiliar?: string[]; @ApiProperty({ description: 'Código da filial', diff --git a/src/products/dto/rotina-a4-query.dto.ts b/src/products/dto/rotina-a4-query.dto.ts index bbb45a3..4162426 100644 --- a/src/products/dto/rotina-a4-query.dto.ts +++ b/src/products/dto/rotina-a4-query.dto.ts @@ -14,12 +14,20 @@ export class RotinaA4QueryDto { numregiao: number; @ApiProperty({ - description: 'Código do produto', + description: 'Código do produto (opcional se codauxiliar for informado)', example: 12345, + required: false, }) @IsNumber() - @IsNotEmpty() - codprod: number; + codprod?: number; + + @ApiProperty({ + description: 'Código auxiliar do produto (opcional se codprod for informado)', + example: '7891234567890', + required: false, + }) + @IsString() + codauxiliar?: string; @ApiProperty({ description: 'Código da filial', diff --git a/src/products/dto/rotina-a4-response.dto.ts b/src/products/dto/rotina-a4-response.dto.ts index d59865c..c26bdfa 100644 --- a/src/products/dto/rotina-a4-response.dto.ts +++ b/src/products/dto/rotina-a4-response.dto.ts @@ -16,6 +16,12 @@ export class RotinaA4ResponseDto { }) CODPROD: number; + @ApiProperty({ + description: 'Código auxiliar do produto', + example: '7891234567890', + }) + CODAUXILIAR: string; + @ApiProperty({ description: 'Preço normal do produto formatado como moeda brasileira (com decimais)', example: '1.109,90', diff --git a/src/products/products.controller.ts b/src/products/products.controller.ts index 9ee0a33..a1fda8f 100644 --- a/src/products/products.controller.ts +++ b/src/products/products.controller.ts @@ -1,14 +1,14 @@ /* eslint-disable prettier/prettier */ /* eslint-disable @typescript-eslint/no-unused-vars */ -import { Body, Controller, Get, Param, Post,UseGuards } from '@nestjs/common'; +import { Body, Controller, Get, Param, Post, Query, UseGuards } from '@nestjs/common'; import { ProductsService } from './products.service'; import { ExposedProduct } from 'src/core/models/exposed-product.model'; import { JwtAuthGuard } from 'src/auth/guards/jwt-auth.guard'; import { ExposedProductDto } from './dto/exposed-product.dto'; import { ProductValidationDto } from './dto/ProductValidationDto'; import { ProductEcommerceDto } from './dto/product-ecommerce.dto'; -import { ApiTags, ApiOperation, ApiParam, ApiBody, ApiResponse, ApiBearerAuth } from '@nestjs/swagger'; +import { ApiTags, ApiOperation, ApiParam, ApiQuery, ApiBody, ApiResponse, ApiBearerAuth } from '@nestjs/swagger'; import { ProductDetailQueryDto } from './dto/product-detail-query.dto'; import { ProductDetailResponseDto } from './dto/product-detail-response.dto'; import { RotinaA4QueryDto } from './dto/rotina-a4-query.dto'; @@ -37,6 +37,7 @@ export class ProductsController { @ApiOperation({ summary: 'Valida produto pelo filtro (código, EAN ou descrição)' }) @ApiParam({ name: 'storeId', type: String, description: 'ID da loja' }) @ApiParam({ name: 'filtro', type: String, description: 'Filtro de busca (código, EAN ou descrição)' }) + @ApiQuery({ name: 'tipoBusca', required: false, enum: ['codauxiliar', 'codprod', 'descricao', 'todos'], description: 'Tipo de busca específica (opcional). Padrão: busca em todos os campos' }) @ApiResponse({ status: 200, description: 'Produto encontrado com sucesso.', @@ -46,8 +47,9 @@ export class ProductsController { async productValidation( @Param('storeId') storeId: string, @Param('filtro') filtro: string, + @Query('tipoBusca') tipoBusca?: 'codauxiliar' | 'codprod' | 'descricao' | 'todos', ): Promise { - return this.productsService.productsValidation(storeId, filtro); + return this.productsService.productsValidation(storeId, filtro, tipoBusca); } diff --git a/src/products/products.service.ts b/src/products/products.service.ts index 6373f10..4a27675 100644 --- a/src/products/products.service.ts +++ b/src/products/products.service.ts @@ -15,48 +15,83 @@ export class ProductsService { @InjectDataSource('oracle') private readonly dataSource: DataSource, ) {} - /** - * Valida e busca informações de um produto por código ou descrição - * @param storeId - Código da filial - * @param filtro - Filtro de busca (código auxiliar, código produto ou descrição) - * @returns Dados do produto encontrado com estoque e preço - * @throws HttpException quando produto não é encontrado - */ + private buildProductsValidationWhereCondition( + tipoBusca?: 'codauxiliar' | 'codprod' | 'descricao' | 'todos', + ): { whereCondition: string; useSingleParam: boolean } { + if (tipoBusca === 'codauxiliar') { + return { + whereCondition: 'PCPRODUT.CODAUXILIAR = REGEXP_REPLACE(:filtro, \'[^0-9]\', \'\')', + useSingleParam: true, + }; + } + + if (tipoBusca === 'codprod') { + return { + whereCondition: 'PCPRODUT.CODPROD = REGEXP_REPLACE(:filtro, \'[^0-9]\', \'\')', + useSingleParam: true, + }; + } + + if (tipoBusca === 'descricao') { + return { + whereCondition: 'PCPRODUT.DESCRICAO LIKE \'%\' || :filtro || \'%\'', + useSingleParam: true, + }; + } + + return { + whereCondition: `( + PCPRODUT.CODAUXILIAR = REGEXP_REPLACE(:filtro1, '[^0-9]', '') + OR PCPRODUT.CODPROD = REGEXP_REPLACE(:filtro2, '[^0-9]', '') + OR PCPRODUT.DESCRICAO LIKE '%' || :filtro3 || '%' + )`, + useSingleParam: false, + }; + } + async productsValidation( storeId: string, filtro: string, + tipoBusca?: 'codauxiliar' | 'codprod' | 'descricao' | 'todos', ): Promise { - const sql = `SELECT PCPRODUT.DESCRICAO as "descricao" - ,PCPRODUT.CODPROD as "codigoProduto" - ,PCPRODUT.CODAUXILIAR as "codigoAuxiliar" - ,PCMARCA.MARCA as "marca" - ,REPLACE(NVL(URLIMAGEM, 'http://10.1.1.191/si.png'), 'http://167.249.211.178:8001/', 'http://10.1.1.191/') as "images" - ,CASE WHEN PCPRODUT.TIPOPRODUTO = 'A' THEN 'AUTOSSERVICO' - WHEN PCPRODUT.TIPOPRODUTO = 'S' THEN 'SHOWROOM' - WHEN PCPRODUT.TIPOPRODUTO = 'E' THEN 'ELETROMOVEIS' - ELSE 'OUTROS' END as "tipoProduto" - ,PCTABPR.PVENDA1 as "precoVenda" - ,( PCEST.QTESTGER - PCEST.QTRESERV - PCEST.QTBLOQUEADA ) as "qtdeEstoqueLoja" - ,( SELECT ( ESTOQUE_CD.QTESTGER - ESTOQUE_CD.QTRESERV - ESTOQUE_CD.QTBLOQUEADA ) - FROM PCEST ESTOQUE_CD - WHERE ESTOQUE_CD.CODPROD = PCPRODUT.CODPROD - AND ESTOQUE_CD.CODFILIAL = 6 ) as "qtdeEstoqueCD" - FROM PCPRODUT, PCEST, PCTABPR, PCMARCA - WHERE PCPRODUT.CODPROD = PCEST.CODPROD - AND PCPRODUT.CODPROD = PCTABPR.CODPROD - AND PCPRODUT.CODMARCA = PCMARCA.CODMARCA - AND PCTABPR.NUMREGIAO = 1 - AND PCEST.CODFILIAL = :storeId - AND ( PCPRODUT.CODAUXILIAR = REGEXP_REPLACE(:filtro1, '[^0-9]', '') OR - PCPRODUT.CODPROD = REGEXP_REPLACE(:filtro2, '[^0-9]', '') OR - PCPRODUT.DESCRICAO LIKE '%'||:filtro3||'%' )`; + const { whereCondition, useSingleParam } = + this.buildProductsValidationWhereCondition(tipoBusca); - const products = await this.dataSource.query(sql, [ - storeId, - filtro, - filtro, - filtro, - ]); + const sql = ` + SELECT + PCPRODUT.DESCRICAO as "descricao", + PCPRODUT.CODPROD as "codigoProduto", + PCPRODUT.CODAUXILIAR as "codigoAuxiliar", + PCMARCA.MARCA as "marca", + REPLACE(NVL(URLIMAGEM, 'http://10.1.1.191/si.png'), 'http://167.249.211.178:8001/', 'http://10.1.1.191/') as "images", + CASE + WHEN PCPRODUT.TIPOPRODUTO = 'A' THEN 'AUTOSSERVICO' + WHEN PCPRODUT.TIPOPRODUTO = 'S' THEN 'SHOWROOM' + WHEN PCPRODUT.TIPOPRODUTO = 'E' THEN 'ELETROMOVEIS' + ELSE 'OUTROS' + END as "tipoProduto", + PCTABPR.PVENDA1 as "precoVenda", + (PCEST.QTESTGER - PCEST.QTRESERV - PCEST.QTBLOQUEADA) as "qtdeEstoqueLoja", + ( + SELECT (ESTOQUE_CD.QTESTGER - ESTOQUE_CD.QTRESERV - ESTOQUE_CD.QTBLOQUEADA) + FROM PCEST ESTOQUE_CD + WHERE ESTOQUE_CD.CODPROD = PCPRODUT.CODPROD + AND ESTOQUE_CD.CODFILIAL = 6 + ) as "qtdeEstoqueCD" + FROM PCPRODUT, PCEST, PCTABPR, PCMARCA + WHERE PCPRODUT.CODPROD = PCEST.CODPROD + AND PCPRODUT.CODPROD = PCTABPR.CODPROD + AND PCPRODUT.CODMARCA = PCMARCA.CODMARCA + AND PCTABPR.NUMREGIAO = 1 + AND PCEST.CODFILIAL = :storeId + AND ${whereCondition} + `; + + const params = useSingleParam + ? [storeId, filtro] + : [storeId, filtro, filtro, filtro]; + + const products = await this.dataSource.query(sql, params); if (products.length === 0) { throw new HttpException('Produto não localizado!', HttpStatus.NOT_FOUND); @@ -66,21 +101,16 @@ export class ProductsService { if (!product.images) { product.images = []; - } else { - product.images = product.images.includes(';') - ? product.images.split(';') - : [product.images]; + return product; } + product.images = product.images.includes(';') + ? product.images.split(';') + : [product.images]; + return product; } - /** - * Registra produto exposto em showroom - * @param product - Dados do produto exposto (storeId, ean, userId) - * @returns Mensagem de sucesso - * @throws Lança exceção em caso de erro na transação - */ async exposedProduct(product: ExposedProduct) { const queryRunner = this.dataSource.createQueryRunner(); await queryRunner.connect(); @@ -104,28 +134,22 @@ export class ProductsService { } } - /** - * Busca produtos disponíveis para e-commerce - * @returns Lista de produtos com preços para e-commerce - */ async getProductsEcommerce(): Promise { - const sql = `SELECT P.CODPROD as "productIdErp" - ,P.VTEXSKUID as "productId" - ,ROUND(P.PVENDA,2) as "price" - ,ROUND(P.PRECOKIT,2) as "priceKit" - FROM ESVPRODUTOSECOMMERCE P - WHERE P.VTEXSKUID > 0 - AND P.CODPROD IN (52057, 33702, 46410, 24518, 25816)`; + const sql = ` + SELECT + P.CODPROD as "productIdErp", + P.VTEXSKUID as "productId", + ROUND(P.PVENDA, 2) as "price", + ROUND(P.PRECOKIT, 2) as "priceKit" + FROM ESVPRODUTOSECOMMERCE P + WHERE P.VTEXSKUID > 0 + AND P.CODPROD IN (52057, 33702, 46410, 24518, 25816) + `; const products = await this.dataSource.query(sql); return products; } - /** - * Formata um valor numérico para o padrão de moeda brasileira - * @param valor - Valor numérico a ser formatado - * @returns String formatada no padrão brasileiro (ex: 1.109,90) - */ private formatarMoedaBrasileira(valor: number): string { if (valor === null || valor === undefined) { return '0,00'; @@ -136,43 +160,144 @@ export class ProductsService { }); } - /** - * Busca detalhes de produtos com preço integrado com região - * @param query - Parâmetros de busca (codprod, numregiao, codfilial) - * @returns Lista de produtos com detalhes - */ + private buildProductDetailsWhereCondition( + codprod: number[] | undefined, + codauxiliar: string[] | undefined, + startParamIndex: number, + ): { whereCondition: string; params: any[]; nextParamIndex: number } { + const hasCodprod = codprod?.length > 0; + const hasCodauxiliar = codauxiliar?.length > 0; + + if (hasCodprod && hasCodauxiliar) { + return this.buildWhereConditionWithBoth(codprod, codauxiliar, startParamIndex); + } + + if (hasCodprod) { + return this.buildWhereConditionWithCodprod(codprod, startParamIndex); + } + + if (hasCodauxiliar) { + return this.buildWhereConditionWithCodauxiliar(codauxiliar, startParamIndex); + } + + return { whereCondition: '', params: [], nextParamIndex: startParamIndex }; + } + + private buildWhereConditionWithBoth( + codprod: number[], + codauxiliar: string[], + startParamIndex: number, + ): { whereCondition: string; params: any[]; nextParamIndex: number } { + let paramIndex = startParamIndex; + const codprodPlaceholders: string[] = []; + const codauxiliarPlaceholders: string[] = []; + const params: any[] = []; + + codprod.forEach(() => { + codprodPlaceholders.push(`:${paramIndex}`); + paramIndex++; + }); + + codauxiliar.forEach(() => { + codauxiliarPlaceholders.push(`:${paramIndex}`); + paramIndex++; + }); + + const whereCondition = `(PCPRODUT.CODPROD IN (${codprodPlaceholders.join(',')}) OR REGEXP_REPLACE(PCPRODUT.CODAUXILIAR, '[^0-9]', '') IN (${codauxiliarPlaceholders.join(',')}))`; + + params.push(...codprod); + codauxiliar.forEach((aux) => { + params.push(aux.replace(/\D/g, '')); + }); + + return { whereCondition, params, nextParamIndex: paramIndex }; + } + + private buildWhereConditionWithCodprod( + codprod: number[], + startParamIndex: number, + ): { whereCondition: string; params: any[]; nextParamIndex: number } { + let paramIndex = startParamIndex; + const placeholders: string[] = []; + + codprod.forEach(() => { + placeholders.push(`:${paramIndex}`); + paramIndex++; + }); + + const whereCondition = `PCPRODUT.CODPROD IN (${placeholders.join(',')})`; + const params = [...codprod]; + + return { whereCondition, params, nextParamIndex: paramIndex }; + } + + private buildWhereConditionWithCodauxiliar( + codauxiliar: string[], + startParamIndex: number, + ): { whereCondition: string; params: any[]; nextParamIndex: number } { + let paramIndex = startParamIndex; + const placeholders: string[] = []; + const params: any[] = []; + + codauxiliar.forEach(() => { + placeholders.push(`:${paramIndex}`); + paramIndex++; + }); + + const whereCondition = `REGEXP_REPLACE(PCPRODUT.CODAUXILIAR, '[^0-9]', '') IN (${placeholders.join(',')})`; + codauxiliar.forEach((aux) => { + params.push(aux.replace(/\D/g, '')); + }); + + return { whereCondition, params, nextParamIndex: paramIndex }; + } + async getProductDetails( query: ProductDetailQueryDto, ): Promise { - const { numregiao, codprod, codfilial } = query; + const { numregiao, codprod, codauxiliar, codfilial } = query; - const placeholders = codprod - .map((_, index) => `:codprod${index}`) - .join(','); + if (!codprod?.length && !codauxiliar?.length) { + throw new HttpException( + 'É necessário informar codprod ou codauxiliar.', + HttpStatus.BAD_REQUEST, + ); + } + + const baseParams: any[] = [numregiao, codfilial, numregiao]; + const { whereCondition, params: whereParams } = + this.buildProductDetailsWhereCondition(codprod, codauxiliar, 4); + + const params = [...baseParams, ...whereParams]; const sql = ` - SELECT + SELECT PCPRODUT.CODPROD AS "codprod", PCPRODUT.DESCRICAO || ' - ' || PCMARCA.MARCA AS "descricao", PCPRODUT.EMBALAGEM AS "embalagem", PCPRODUT.CODAUXILIAR AS "codauxiliar", PCMARCA.MARCA AS "marca", - (SELECT PCTABPR.PVENDA1 - FROM PCTABPR + ( + SELECT PCTABPR.PVENDA1 + FROM PCTABPR WHERE PCTABPR.CODPROD = PCPRODUT.CODPROD - AND PCTABPR.NUMREGIAO = :numregiao1) AS "preco", - (SELECT TRIM(REPLACE(RAZAOSOCIAL, 'LTDA', '')) - FROM PCFILIAL F - WHERE CODIGO = :codfilial) AS "filial", - (SELECT REGIAO - FROM PCREGIAO - WHERE NUMREGIAO = :numregiao2) AS "regiao" + AND PCTABPR.NUMREGIAO = :1 + ) AS "preco", + ( + SELECT TRIM(REPLACE(RAZAOSOCIAL, 'LTDA', '')) + FROM PCFILIAL F + WHERE CODIGO = :2 + ) AS "filial", + ( + SELECT REGIAO + FROM PCREGIAO + WHERE NUMREGIAO = :3 + ) AS "regiao" FROM PCPRODUT LEFT JOIN PCMARCA ON PCPRODUT.CODMARCA = PCMARCA.CODMARCA - WHERE PCPRODUT.CODPROD IN (${placeholders}) + WHERE ${whereCondition} `; - const params = [numregiao, codfilial, numregiao, ...codprod]; const products = await this.dataSource.query(sql, params); return products.map((product) => ({ @@ -181,67 +306,129 @@ export class ProductsService { })); } - /** - * Busca informações do produto conforme rotina A4 - * @param query - Parâmetros de busca (numregiao, codprod, codfilial) - * @returns Dados do produto conforme rotina A4 - */ + private buildRotinaA4WhereCondition( + codprod: number | undefined, + codauxiliar: string | undefined, + ): { whereCondition: string; params: any[] } { + const hasCodprod = !!codprod; + const hasCodauxiliar = !!codauxiliar; + + if (hasCodprod && hasCodauxiliar) { + return { + whereCondition: + 'and (pcprodut.codprod = :3 OR REGEXP_REPLACE(pcprodut.CODAUXILIAR, \'[^0-9]\', \'\') = REGEXP_REPLACE(:4, \'[^0-9]\', \'\'))', + params: [codprod, codauxiliar], + }; + } + + if (hasCodprod) { + return { + whereCondition: 'and pcprodut.codprod = :3', + params: [codprod], + }; + } + + if (hasCodauxiliar) { + return { + whereCondition: + 'and REGEXP_REPLACE(pcprodut.CODAUXILIAR, \'[^0-9]\', \'\') = REGEXP_REPLACE(:3, \'[^0-9]\', \'\')', + params: [codauxiliar], + }; + } + + return { whereCondition: '', params: [] }; + } + async getRotinaA4(query: RotinaA4QueryDto): Promise { - const { numregiao, codprod, codfilial } = query; + const { numregiao, codprod, codauxiliar, codfilial } = query; + + if (!codprod && !codauxiliar) { + throw new HttpException( + 'É necessário informar codprod ou codauxiliar.', + HttpStatus.BAD_REQUEST, + ); + } + + const baseParams: any[] = [numregiao, codfilial]; + const { whereCondition, params: whereParams } = + this.buildRotinaA4WhereCondition(codprod, codauxiliar); + + const params = [...baseParams, ...whereParams]; const sql = ` - SELECT + SELECT DADOS.DESCRICAO, DADOS.CODPROD, + DADOS.CODAUXILIAR, DADOS.PRECO_NORMAL, DADOS.UNIDADE, - TRUNC(DADOS.VALOR_VENDA,0) VALOR_VENDA, - REPLACE(REPLACE(TO_CHAR( (DADOS.VALOR_VENDA - TRUNC(DADOS.VALOR_VENDA,0)) ,'FM999G9D00'),',',''),'.','') DECIMAL_VENDA, + TRUNC(DADOS.VALOR_VENDA, 0) VALOR_VENDA, + REPLACE( + REPLACE( + TO_CHAR((DADOS.VALOR_VENDA - TRUNC(DADOS.VALOR_VENDA, 0)), 'FM999G9D00'), + ',', + '' + ), + '.', + '' + ) DECIMAL_VENDA, DADOS.MARCA - FROM - (SELECT + FROM ( + SELECT pcprodut.DESCRICAO, - pcprodut.embalagem as unidade, + pcprodut.embalagem as unidade, pctabpr.PVENDA PRECO_NORMAL, pcprodut.CODPROD, - TRUNC(pctabpr.PVENDA1,2) PVENDA1, - (CASE WHEN - NVL(TRUNC((SELECT P.PRECOFIXO - FROM PCPRECOPROM P + pcprodut.CODAUXILIAR, + TRUNC(pctabpr.PVENDA1, 2) PVENDA1, + ( + CASE + WHEN NVL( + TRUNC( + ( + SELECT P.PRECOFIXO + FROM PCPRECOPROM P + WHERE P.CODPROD = PCTABPR.CODPROD + AND TRUNC(SYSDATE) BETWEEN P.DTINICIOVIGENCIA AND P.DTFIMVIGENCIA + AND (P.CODPLPAGMAX = 10 OR P.CODPLPAGMAX = 1) + AND ROWNUM = 1 + AND P.NUMREGIAO = PCTABPR.NUMREGIAO + ), + 1 + ), + 0 + ) = 0 THEN PCTABPR.PVENDA1 + ELSE TRUNC( + ( + SELECT P.PRECOFIXO + FROM PCPRECOPROM P WHERE P.CODPROD = PCTABPR.CODPROD - AND TRUNC(SYSDATE) BETWEEN P.DTINICIOVIGENCIA AND P.DTFIMVIGENCIA - AND (P.CODPLPAGMAX = 10 OR P.CODPLPAGMAX = 1) - AND ROWNUM = 1 - AND P.NUMREGIAO = PCTABPR.NUMREGIAO),1) ,0) = 0 - THEN PCTABPR.PVENDA1 - ELSE - TRUNC((SELECT P.PRECOFIXO - FROM PCPRECOPROM P - WHERE P.CODPROD = PCTABPR.CODPROD - AND TRUNC(SYSDATE) BETWEEN P.DTINICIOVIGENCIA AND P.DTFIMVIGENCIA - AND (P.CODPLPAGMAX = 10 OR P.CODPLPAGMAX = 1) - AND ROWNUM = 1 - AND P.NUMREGIAO = PCTABPR.NUMREGIAO),2) END ) VALOR_VENDA, - (select marca from pcmarca where pcmarca.codmarca = pcprodut.codmarca)marca - FROM - pctabpr, - pcprodut, - pcest - WHERE - pctabpr.CODPROD = pcprodut.CODPROD - and pcest.codprod = pctabpr.CODPROD - AND pctabpr.NUMREGIAO = :numregiao - and pcprodut.DTEXCLUSAO is null - and pcprodut.codprod = :codprod - AND pcest.codfilial = :codfilial - and pctabpr.PVENDA is not null ) DADOS + AND TRUNC(SYSDATE) BETWEEN P.DTINICIOVIGENCIA AND P.DTFIMVIGENCIA + AND (P.CODPLPAGMAX = 10 OR P.CODPLPAGMAX = 1) + AND ROWNUM = 1 + AND P.NUMREGIAO = PCTABPR.NUMREGIAO + ), + 2 + ) + END + ) VALOR_VENDA, + ( + SELECT marca + FROM pcmarca + WHERE pcmarca.codmarca = pcprodut.codmarca + ) marca + FROM pctabpr, pcprodut, pcest + WHERE pctabpr.CODPROD = pcprodut.CODPROD + AND pcest.codprod = pctabpr.CODPROD + AND pctabpr.NUMREGIAO = :1 + AND pcprodut.DTEXCLUSAO is null + AND pcest.codfilial = :2 + AND pctabpr.PVENDA is not null + ${whereCondition} + ) DADOS `; - const result = await this.dataSource.query(sql, [ - numregiao, - codprod, - codfilial, - ]); + const result = await this.dataSource.query(sql, params); if (result.length === 0) { throw new HttpException( @@ -251,22 +438,14 @@ export class ProductsService { } const produto = result[0]; - - /** - * Formata o preço normal como moeda brasileira com decimais - * Exemplo: 1109.9 -> "1.109,90" - */ + if (produto.PRECO_NORMAL !== null && produto.PRECO_NORMAL !== undefined) { produto.PRECO_NORMAL = produto.PRECO_NORMAL.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2, }); } - - /** - * Formata o valor de venda como moeda brasileira sem decimais - * Exemplo: 2499 -> "R$ 2.499" - */ + if (produto.VALOR_VENDA !== null && produto.VALOR_VENDA !== undefined) { produto.VALOR_VENDA = `R$ ${produto.VALOR_VENDA.toLocaleString('pt-BR', { minimumFractionDigits: 0,