Atualizações em data-consult e products

This commit is contained in:
joelson brito
2025-11-10 12:39:31 -03:00
parent b8630adf92
commit 054cc2f3bb
8 changed files with 396 additions and 150 deletions

View File

@@ -83,6 +83,20 @@ export class DataConsultController {
return this.dataConsultService.customers(filter); 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<ProductDto[]> {
return this.dataConsultService.productsByCodauxiliar(codauxiliar);
}
@UseGuards(JwtAuthGuard) @UseGuards(JwtAuthGuard)
@ApiBearerAuth() @ApiBearerAuth()
@Get('products/:filter') @Get('products/:filter')

View File

@@ -126,6 +126,17 @@ export class DataConsultRepository {
return results.map((result) => new ProductDto(result)); return results.map((result) => new ProductDto(result));
} }
async findProductsByCodauxiliar(codauxiliar: string): Promise<ProductDto[]> {
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<ProductDto[]> { async findAllProducts(): Promise<ProductDto[]> {
const sql = ` const sql = `
SELECT PCPRODUT.CODPROD as "id", SELECT PCPRODUT.CODPROD as "id",

View File

@@ -227,6 +227,23 @@ export class DataConsultService {
} }
} }
async productsByCodauxiliar(codauxiliar: string): Promise<ProductDto[]> {
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<ProductDto[]> { async getAllProducts(): Promise<ProductDto[]> {
this.logger.log('Buscando todos os produtos'); this.logger.log('Buscando todos os produtos');
try { try {

View File

@@ -14,13 +14,22 @@ export class ProductDetailQueryDto {
numregiao: number; numregiao: number;
@ApiProperty({ @ApiProperty({
description: 'Array de códigos de produtos', description: 'Array de códigos de produtos (opcional se codauxiliar for informado)',
example: [1, 2, 3], example: [1, 2, 3],
type: [Number], type: [Number],
required: false,
}) })
@IsArray() @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({ @ApiProperty({
description: 'Código da filial', description: 'Código da filial',

View File

@@ -14,12 +14,20 @@ export class RotinaA4QueryDto {
numregiao: number; numregiao: number;
@ApiProperty({ @ApiProperty({
description: 'Código do produto', description: 'Código do produto (opcional se codauxiliar for informado)',
example: 12345, example: 12345,
required: false,
}) })
@IsNumber() @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({ @ApiProperty({
description: 'Código da filial', description: 'Código da filial',

View File

@@ -16,6 +16,12 @@ export class RotinaA4ResponseDto {
}) })
CODPROD: number; CODPROD: number;
@ApiProperty({
description: 'Código auxiliar do produto',
example: '7891234567890',
})
CODAUXILIAR: string;
@ApiProperty({ @ApiProperty({
description: 'Preço normal do produto formatado como moeda brasileira (com decimais)', description: 'Preço normal do produto formatado como moeda brasileira (com decimais)',
example: '1.109,90', example: '1.109,90',

View File

@@ -1,14 +1,14 @@
/* eslint-disable prettier/prettier */ /* eslint-disable prettier/prettier */
/* eslint-disable @typescript-eslint/no-unused-vars */ /* 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 { ProductsService } from './products.service';
import { ExposedProduct } from 'src/core/models/exposed-product.model'; import { ExposedProduct } from 'src/core/models/exposed-product.model';
import { JwtAuthGuard } from 'src/auth/guards/jwt-auth.guard'; import { JwtAuthGuard } from 'src/auth/guards/jwt-auth.guard';
import { ExposedProductDto } from './dto/exposed-product.dto'; import { ExposedProductDto } from './dto/exposed-product.dto';
import { ProductValidationDto } from './dto/ProductValidationDto'; import { ProductValidationDto } from './dto/ProductValidationDto';
import { ProductEcommerceDto } from './dto/product-ecommerce.dto'; 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 { ProductDetailQueryDto } from './dto/product-detail-query.dto';
import { ProductDetailResponseDto } from './dto/product-detail-response.dto'; import { ProductDetailResponseDto } from './dto/product-detail-response.dto';
import { RotinaA4QueryDto } from './dto/rotina-a4-query.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)' }) @ApiOperation({ summary: 'Valida produto pelo filtro (código, EAN ou descrição)' })
@ApiParam({ name: 'storeId', type: String, description: 'ID da loja' }) @ApiParam({ name: 'storeId', type: String, description: 'ID da loja' })
@ApiParam({ name: 'filtro', type: String, description: 'Filtro de busca (código, EAN ou descrição)' }) @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({ @ApiResponse({
status: 200, status: 200,
description: 'Produto encontrado com sucesso.', description: 'Produto encontrado com sucesso.',
@@ -46,8 +47,9 @@ export class ProductsController {
async productValidation( async productValidation(
@Param('storeId') storeId: string, @Param('storeId') storeId: string,
@Param('filtro') filtro: string, @Param('filtro') filtro: string,
@Query('tipoBusca') tipoBusca?: 'codauxiliar' | 'codprod' | 'descricao' | 'todos',
): Promise<ProductValidationDto> { ): Promise<ProductValidationDto> {
return this.productsService.productsValidation(storeId, filtro); return this.productsService.productsValidation(storeId, filtro, tipoBusca);
} }

View File

@@ -15,48 +15,83 @@ export class ProductsService {
@InjectDataSource('oracle') private readonly dataSource: DataSource, @InjectDataSource('oracle') private readonly dataSource: DataSource,
) {} ) {}
/** private buildProductsValidationWhereCondition(
* Valida e busca informações de um produto por código ou descrição tipoBusca?: 'codauxiliar' | 'codprod' | 'descricao' | 'todos',
* @param storeId - Código da filial ): { whereCondition: string; useSingleParam: boolean } {
* @param filtro - Filtro de busca (código auxiliar, código produto ou descrição) if (tipoBusca === 'codauxiliar') {
* @returns Dados do produto encontrado com estoque e preço return {
* @throws HttpException quando produto não é encontrado 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( async productsValidation(
storeId: string, storeId: string,
filtro: string, filtro: string,
tipoBusca?: 'codauxiliar' | 'codprod' | 'descricao' | 'todos',
): Promise<ProductValidationDto> { ): Promise<ProductValidationDto> {
const sql = `SELECT PCPRODUT.DESCRICAO as "descricao" const { whereCondition, useSingleParam } =
,PCPRODUT.CODPROD as "codigoProduto" this.buildProductsValidationWhereCondition(tipoBusca);
,PCPRODUT.CODAUXILIAR as "codigoAuxiliar"
,PCMARCA.MARCA as "marca" const sql = `
,REPLACE(NVL(URLIMAGEM, 'http://10.1.1.191/si.png'), 'http://167.249.211.178:8001/', 'http://10.1.1.191/') as "images" SELECT
,CASE WHEN PCPRODUT.TIPOPRODUTO = 'A' THEN 'AUTOSSERVICO' 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 = 'S' THEN 'SHOWROOM'
WHEN PCPRODUT.TIPOPRODUTO = 'E' THEN 'ELETROMOVEIS' WHEN PCPRODUT.TIPOPRODUTO = 'E' THEN 'ELETROMOVEIS'
ELSE 'OUTROS' END as "tipoProduto" ELSE 'OUTROS'
,PCTABPR.PVENDA1 as "precoVenda" END as "tipoProduto",
,( PCEST.QTESTGER - PCEST.QTRESERV - PCEST.QTBLOQUEADA ) as "qtdeEstoqueLoja" PCTABPR.PVENDA1 as "precoVenda",
,( SELECT ( ESTOQUE_CD.QTESTGER - ESTOQUE_CD.QTRESERV - ESTOQUE_CD.QTBLOQUEADA ) (PCEST.QTESTGER - PCEST.QTRESERV - PCEST.QTBLOQUEADA) as "qtdeEstoqueLoja",
(
SELECT (ESTOQUE_CD.QTESTGER - ESTOQUE_CD.QTRESERV - ESTOQUE_CD.QTBLOQUEADA)
FROM PCEST ESTOQUE_CD FROM PCEST ESTOQUE_CD
WHERE ESTOQUE_CD.CODPROD = PCPRODUT.CODPROD WHERE ESTOQUE_CD.CODPROD = PCPRODUT.CODPROD
AND ESTOQUE_CD.CODFILIAL = 6 ) as "qtdeEstoqueCD" AND ESTOQUE_CD.CODFILIAL = 6
) as "qtdeEstoqueCD"
FROM PCPRODUT, PCEST, PCTABPR, PCMARCA FROM PCPRODUT, PCEST, PCTABPR, PCMARCA
WHERE PCPRODUT.CODPROD = PCEST.CODPROD WHERE PCPRODUT.CODPROD = PCEST.CODPROD
AND PCPRODUT.CODPROD = PCTABPR.CODPROD AND PCPRODUT.CODPROD = PCTABPR.CODPROD
AND PCPRODUT.CODMARCA = PCMARCA.CODMARCA AND PCPRODUT.CODMARCA = PCMARCA.CODMARCA
AND PCTABPR.NUMREGIAO = 1 AND PCTABPR.NUMREGIAO = 1
AND PCEST.CODFILIAL = :storeId AND PCEST.CODFILIAL = :storeId
AND ( PCPRODUT.CODAUXILIAR = REGEXP_REPLACE(:filtro1, '[^0-9]', '') OR AND ${whereCondition}
PCPRODUT.CODPROD = REGEXP_REPLACE(:filtro2, '[^0-9]', '') OR `;
PCPRODUT.DESCRICAO LIKE '%'||:filtro3||'%' )`;
const products = await this.dataSource.query(sql, [ const params = useSingleParam
storeId, ? [storeId, filtro]
filtro, : [storeId, filtro, filtro, filtro];
filtro,
filtro, const products = await this.dataSource.query(sql, params);
]);
if (products.length === 0) { if (products.length === 0) {
throw new HttpException('Produto não localizado!', HttpStatus.NOT_FOUND); throw new HttpException('Produto não localizado!', HttpStatus.NOT_FOUND);
@@ -66,21 +101,16 @@ export class ProductsService {
if (!product.images) { if (!product.images) {
product.images = []; product.images = [];
} else { return product;
}
product.images = product.images.includes(';') product.images = product.images.includes(';')
? product.images.split(';') ? product.images.split(';')
: [product.images]; : [product.images];
}
return product; 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) { async exposedProduct(product: ExposedProduct) {
const queryRunner = this.dataSource.createQueryRunner(); const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.connect(); 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<ProductEcommerceDto[]> { async getProductsEcommerce(): Promise<ProductEcommerceDto[]> {
const sql = `SELECT P.CODPROD as "productIdErp" const sql = `
,P.VTEXSKUID as "productId" SELECT
,ROUND(P.PVENDA,2) as "price" P.CODPROD as "productIdErp",
,ROUND(P.PRECOKIT,2) as "priceKit" P.VTEXSKUID as "productId",
ROUND(P.PVENDA, 2) as "price",
ROUND(P.PRECOKIT, 2) as "priceKit"
FROM ESVPRODUTOSECOMMERCE P FROM ESVPRODUTOSECOMMERCE P
WHERE P.VTEXSKUID > 0 WHERE P.VTEXSKUID > 0
AND P.CODPROD IN (52057, 33702, 46410, 24518, 25816)`; AND P.CODPROD IN (52057, 33702, 46410, 24518, 25816)
`;
const products = await this.dataSource.query(sql); const products = await this.dataSource.query(sql);
return products; 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 { private formatarMoedaBrasileira(valor: number): string {
if (valor === null || valor === undefined) { if (valor === null || valor === undefined) {
return '0,00'; return '0,00';
@@ -136,19 +160,115 @@ export class ProductsService {
}); });
} }
/** private buildProductDetailsWhereCondition(
* Busca detalhes de produtos com preço integrado com região codprod: number[] | undefined,
* @param query - Parâmetros de busca (codprod, numregiao, codfilial) codauxiliar: string[] | undefined,
* @returns Lista de produtos com detalhes 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( async getProductDetails(
query: ProductDetailQueryDto, query: ProductDetailQueryDto,
): Promise<ProductDetailResponseDto[]> { ): Promise<ProductDetailResponseDto[]> {
const { numregiao, codprod, codfilial } = query; const { numregiao, codprod, codauxiliar, codfilial } = query;
const placeholders = codprod if (!codprod?.length && !codauxiliar?.length) {
.map((_, index) => `:codprod${index}`) throw new HttpException(
.join(','); 'É 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 = ` const sql = `
SELECT SELECT
@@ -157,22 +277,27 @@ export class ProductsService {
PCPRODUT.EMBALAGEM AS "embalagem", PCPRODUT.EMBALAGEM AS "embalagem",
PCPRODUT.CODAUXILIAR AS "codauxiliar", PCPRODUT.CODAUXILIAR AS "codauxiliar",
PCMARCA.MARCA AS "marca", PCMARCA.MARCA AS "marca",
(SELECT PCTABPR.PVENDA1 (
SELECT PCTABPR.PVENDA1
FROM PCTABPR FROM PCTABPR
WHERE PCTABPR.CODPROD = PCPRODUT.CODPROD WHERE PCTABPR.CODPROD = PCPRODUT.CODPROD
AND PCTABPR.NUMREGIAO = :numregiao1) AS "preco", AND PCTABPR.NUMREGIAO = :1
(SELECT TRIM(REPLACE(RAZAOSOCIAL, 'LTDA', '')) ) AS "preco",
(
SELECT TRIM(REPLACE(RAZAOSOCIAL, 'LTDA', ''))
FROM PCFILIAL F FROM PCFILIAL F
WHERE CODIGO = :codfilial) AS "filial", WHERE CODIGO = :2
(SELECT REGIAO ) AS "filial",
(
SELECT REGIAO
FROM PCREGIAO FROM PCREGIAO
WHERE NUMREGIAO = :numregiao2) AS "regiao" WHERE NUMREGIAO = :3
) AS "regiao"
FROM PCPRODUT FROM PCPRODUT
LEFT JOIN PCMARCA ON PCPRODUT.CODMARCA = PCMARCA.CODMARCA 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); const products = await this.dataSource.query(sql, params);
return products.map((product) => ({ return products.map((product) => ({
@@ -181,67 +306,129 @@ export class ProductsService {
})); }));
} }
/** private buildRotinaA4WhereCondition(
* Busca informações do produto conforme rotina A4 codprod: number | undefined,
* @param query - Parâmetros de busca (numregiao, codprod, codfilial) codauxiliar: string | undefined,
* @returns Dados do produto conforme rotina A4 ): { 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<RotinaA4ResponseDto> { async getRotinaA4(query: RotinaA4QueryDto): Promise<RotinaA4ResponseDto> {
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 = ` const sql = `
SELECT SELECT
DADOS.DESCRICAO, DADOS.DESCRICAO,
DADOS.CODPROD, DADOS.CODPROD,
DADOS.CODAUXILIAR,
DADOS.PRECO_NORMAL, DADOS.PRECO_NORMAL,
DADOS.UNIDADE, DADOS.UNIDADE,
TRUNC(DADOS.VALOR_VENDA, 0) VALOR_VENDA, TRUNC(DADOS.VALOR_VENDA, 0) VALOR_VENDA,
REPLACE(REPLACE(TO_CHAR( (DADOS.VALOR_VENDA - TRUNC(DADOS.VALOR_VENDA,0)) ,'FM999G9D00'),',',''),'.','') DECIMAL_VENDA, REPLACE(
REPLACE(
TO_CHAR((DADOS.VALOR_VENDA - TRUNC(DADOS.VALOR_VENDA, 0)), 'FM999G9D00'),
',',
''
),
'.',
''
) DECIMAL_VENDA,
DADOS.MARCA DADOS.MARCA
FROM FROM (
(SELECT SELECT
pcprodut.DESCRICAO, pcprodut.DESCRICAO,
pcprodut.embalagem as unidade, pcprodut.embalagem as unidade,
pctabpr.PVENDA PRECO_NORMAL, pctabpr.PVENDA PRECO_NORMAL,
pcprodut.CODPROD, pcprodut.CODPROD,
pcprodut.CODAUXILIAR,
TRUNC(pctabpr.PVENDA1, 2) PVENDA1, TRUNC(pctabpr.PVENDA1, 2) PVENDA1,
(CASE WHEN (
NVL(TRUNC((SELECT P.PRECOFIXO CASE
WHEN NVL(
TRUNC(
(
SELECT P.PRECOFIXO
FROM PCPRECOPROM P FROM PCPRECOPROM P
WHERE P.CODPROD = PCTABPR.CODPROD WHERE P.CODPROD = PCTABPR.CODPROD
AND TRUNC(SYSDATE) BETWEEN P.DTINICIOVIGENCIA AND P.DTFIMVIGENCIA AND TRUNC(SYSDATE) BETWEEN P.DTINICIOVIGENCIA AND P.DTFIMVIGENCIA
AND (P.CODPLPAGMAX = 10 OR P.CODPLPAGMAX = 1) AND (P.CODPLPAGMAX = 10 OR P.CODPLPAGMAX = 1)
AND ROWNUM = 1 AND ROWNUM = 1
AND P.NUMREGIAO = PCTABPR.NUMREGIAO),1) ,0) = 0 AND P.NUMREGIAO = PCTABPR.NUMREGIAO
THEN PCTABPR.PVENDA1 ),
ELSE 1
TRUNC((SELECT P.PRECOFIXO ),
0
) = 0 THEN PCTABPR.PVENDA1
ELSE TRUNC(
(
SELECT P.PRECOFIXO
FROM PCPRECOPROM P FROM PCPRECOPROM P
WHERE P.CODPROD = PCTABPR.CODPROD WHERE P.CODPROD = PCTABPR.CODPROD
AND TRUNC(SYSDATE) BETWEEN P.DTINICIOVIGENCIA AND P.DTFIMVIGENCIA AND TRUNC(SYSDATE) BETWEEN P.DTINICIOVIGENCIA AND P.DTFIMVIGENCIA
AND (P.CODPLPAGMAX = 10 OR P.CODPLPAGMAX = 1) AND (P.CODPLPAGMAX = 10 OR P.CODPLPAGMAX = 1)
AND ROWNUM = 1 AND ROWNUM = 1
AND P.NUMREGIAO = PCTABPR.NUMREGIAO),2) END ) VALOR_VENDA, AND P.NUMREGIAO = PCTABPR.NUMREGIAO
(select marca from pcmarca where pcmarca.codmarca = pcprodut.codmarca)marca ),
FROM 2
pctabpr, )
pcprodut, END
pcest ) VALOR_VENDA,
WHERE (
pctabpr.CODPROD = pcprodut.CODPROD SELECT marca
and pcest.codprod = pctabpr.CODPROD FROM pcmarca
AND pctabpr.NUMREGIAO = :numregiao WHERE pcmarca.codmarca = pcprodut.codmarca
and pcprodut.DTEXCLUSAO is null ) marca
and pcprodut.codprod = :codprod FROM pctabpr, pcprodut, pcest
AND pcest.codfilial = :codfilial WHERE pctabpr.CODPROD = pcprodut.CODPROD
and pctabpr.PVENDA is not null ) DADOS 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, [ const result = await this.dataSource.query(sql, params);
numregiao,
codprod,
codfilial,
]);
if (result.length === 0) { if (result.length === 0) {
throw new HttpException( throw new HttpException(
@@ -252,10 +439,6 @@ export class ProductsService {
const produto = result[0]; 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) { if (produto.PRECO_NORMAL !== null && produto.PRECO_NORMAL !== undefined) {
produto.PRECO_NORMAL = produto.PRECO_NORMAL.toLocaleString('pt-BR', { produto.PRECO_NORMAL = produto.PRECO_NORMAL.toLocaleString('pt-BR', {
minimumFractionDigits: 2, minimumFractionDigits: 2,
@@ -263,10 +446,6 @@ export class ProductsService {
}); });
} }
/**
* Formata o valor de venda como moeda brasileira sem decimais
* Exemplo: 2499 -> "R$ 2.499"
*/
if (produto.VALOR_VENDA !== null && produto.VALOR_VENDA !== undefined) { if (produto.VALOR_VENDA !== null && produto.VALOR_VENDA !== undefined) {
produto.VALOR_VENDA = `R$ ${produto.VALOR_VENDA.toLocaleString('pt-BR', { produto.VALOR_VENDA = `R$ ${produto.VALOR_VENDA.toLocaleString('pt-BR', {
minimumFractionDigits: 0, minimumFractionDigits: 0,