feat: adiciona endpoint oferta-8026 para buscar ofertas promocionais
This commit is contained in:
36
src/products/dto/oferta-8026-query.dto.ts
Normal file
36
src/products/dto/oferta-8026-query.dto.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsArray, IsNotEmpty, IsNumber, IsString, Matches } from 'class-validator';
|
||||
|
||||
/**
|
||||
* DTO para requisição de ofertas 8026
|
||||
*/
|
||||
export class Oferta8026QueryDto {
|
||||
@ApiProperty({
|
||||
description: 'Data de início da vigência da promoção (formato DD/MM/YYYY)',
|
||||
example: '19/11/2025',
|
||||
})
|
||||
@IsString()
|
||||
@Matches(/^\d{2}\/\d{2}\/\d{4}$/, {
|
||||
message: 'Data deve estar no formato DD/MM/YYYY',
|
||||
})
|
||||
@IsNotEmpty()
|
||||
data: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Array de códigos de produtos',
|
||||
example: [62602],
|
||||
type: [Number],
|
||||
})
|
||||
@IsArray()
|
||||
@IsNotEmpty()
|
||||
codprod: number[];
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Número da região',
|
||||
example: 1,
|
||||
})
|
||||
@IsNumber()
|
||||
@IsNotEmpty()
|
||||
numregiao: number;
|
||||
}
|
||||
|
||||
76
src/products/dto/oferta-8026-response.dto.ts
Normal file
76
src/products/dto/oferta-8026-response.dto.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
/**
|
||||
* DTO para resposta de ofertas 8026
|
||||
*/
|
||||
export class Oferta8026ResponseDto {
|
||||
@ApiProperty({
|
||||
description: 'Código do produto',
|
||||
example: 12345,
|
||||
})
|
||||
codprod: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Descrição do produto',
|
||||
example: 'PRODUTO EXEMPLO',
|
||||
})
|
||||
descricao: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Marca do produto',
|
||||
example: 'MARCA EXEMPLO',
|
||||
})
|
||||
marca: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Unidade do produto',
|
||||
example: 'UN',
|
||||
})
|
||||
unidade: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Preço de venda 1',
|
||||
example: 99.9,
|
||||
})
|
||||
pvenda1: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Preço fixo promocional',
|
||||
example: 79.9,
|
||||
})
|
||||
precofixo: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Percentual de desconto',
|
||||
example: 20,
|
||||
})
|
||||
percdesconto: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Data de fim da vigência',
|
||||
example: '2024-12-31',
|
||||
})
|
||||
dtfimvigencia: Date;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Mensagem para débito',
|
||||
example: 'DEBITO',
|
||||
required: false,
|
||||
})
|
||||
mensagem2: string | null;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Mensagem para à vista',
|
||||
example: 'À VISTA',
|
||||
required: false,
|
||||
})
|
||||
mensagem3: string | null;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Mensagem para 10x',
|
||||
example: '10X',
|
||||
required: false,
|
||||
})
|
||||
mensagem4: string | null;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ import { ProductDetailResponseDto } from './dto/product-detail-response.dto';
|
||||
import { RotinaA4QueryDto } from './dto/rotina-a4-query.dto';
|
||||
import { RotinaA4ResponseDto } from './dto/rotina-a4-response.dto';
|
||||
import { UnifiedProductSearchDto } from './dto/unified-product-search.dto';
|
||||
import { Oferta8026QueryDto } from './dto/oferta-8026-query.dto';
|
||||
import { Oferta8026ResponseDto } from './dto/oferta-8026-response.dto';
|
||||
|
||||
//@ApiBearerAuth()
|
||||
//@UseGuards(JwtAuthGuard)
|
||||
@@ -151,4 +153,23 @@ export class ProductsController {
|
||||
): Promise<ProductDetailResponseDto[]> {
|
||||
return this.productsService.unifiedProductSearch(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Endpoint para buscar ofertas 8026
|
||||
*/
|
||||
@Post('oferta-8026')
|
||||
@ApiOperation({ summary: 'Busca ofertas 8026 conforme parâmetros específicos' })
|
||||
@ApiBody({ type: Oferta8026QueryDto })
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Lista de ofertas retornada com sucesso.',
|
||||
type: Oferta8026ResponseDto,
|
||||
isArray: true,
|
||||
})
|
||||
@ApiResponse({ status: 400, description: 'Parâmetros inválidos.' })
|
||||
async getOferta8026(
|
||||
@Body() query: Oferta8026QueryDto,
|
||||
): Promise<Oferta8026ResponseDto[]> {
|
||||
return this.productsService.getOferta8026(query);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ import { ProductDetailResponseDto } from './dto/product-detail-response.dto';
|
||||
import { RotinaA4QueryDto } from './dto/rotina-a4-query.dto';
|
||||
import { RotinaA4ResponseDto } from './dto/rotina-a4-response.dto';
|
||||
import { UnifiedProductSearchDto } from './dto/unified-product-search.dto';
|
||||
import { Oferta8026QueryDto } from './dto/oferta-8026-query.dto';
|
||||
import { Oferta8026ResponseDto } from './dto/oferta-8026-response.dto';
|
||||
|
||||
@Injectable()
|
||||
export class ProductsService {
|
||||
@@ -322,9 +324,6 @@ export class ProductsService {
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Busca unificada de produtos por nome, código de barras ou codprod
|
||||
*/
|
||||
async unifiedProductSearch(
|
||||
query: UnifiedProductSearchDto,
|
||||
): Promise<ProductDetailResponseDto[]> {
|
||||
@@ -548,4 +547,85 @@ export class ProductsService {
|
||||
|
||||
return produto;
|
||||
}
|
||||
|
||||
async getOferta8026(
|
||||
query: Oferta8026QueryDto,
|
||||
): Promise<Oferta8026ResponseDto[]> {
|
||||
const { data, codprod, numregiao } = query;
|
||||
|
||||
if (!codprod || codprod.length === 0) {
|
||||
throw new HttpException(
|
||||
'É necessário informar pelo menos um código de produto.',
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
}
|
||||
|
||||
let dataFormatada = data;
|
||||
const dateMatch = data.match(/^(\d{2})\/(\d{2})\/(\d{4})$/);
|
||||
if (dateMatch) {
|
||||
const [, part1, part2, year] = dateMatch;
|
||||
const num2 = parseInt(part2, 10);
|
||||
|
||||
dataFormatada = num2 > 12
|
||||
? `${part2}/${part1}/${year}`
|
||||
: `${part1}/${part2}/${year}`;
|
||||
}
|
||||
|
||||
const codprodPlaceholders: string[] = [];
|
||||
const params: any[] = [];
|
||||
let paramIndex = 0;
|
||||
|
||||
params.push(dataFormatada);
|
||||
paramIndex++;
|
||||
|
||||
codprod.forEach((cod) => {
|
||||
codprodPlaceholders.push(`:${paramIndex}`);
|
||||
params.push(cod);
|
||||
paramIndex++;
|
||||
});
|
||||
|
||||
params.push(numregiao);
|
||||
|
||||
const sql = `
|
||||
SELECT
|
||||
pctabpr.codprod,
|
||||
pcprodut.descricao,
|
||||
pcmarca.marca,
|
||||
pcprodut.unidade,
|
||||
pctabpr.pvenda1,
|
||||
pcprecoprom.precofixo,
|
||||
TRUNC(((pctabpr.pvenda1 - pcprecoprom.precofixo) / pctabpr.pvenda1) * 100, 0) percdesconto,
|
||||
pcprecoprom.dtfimvigencia,
|
||||
CASE WHEN pcprecoprom.codplpagmax = 2 THEN 'DEBITO' ELSE NULL END mensagem2,
|
||||
CASE WHEN pcprecoprom.codplpagmax = 10 THEN 'À VISTA' ELSE NULL END mensagem3,
|
||||
CASE WHEN pcprecoprom.codplpagmax = 42 OR pcprecoprom.codplpagmax = 46 THEN '10X' ELSE NULL END mensagem4
|
||||
FROM pctabpr, pcprecoprom, pcplpag, pcprodut, pcmarca
|
||||
WHERE pctabpr.codprod = pcprecoprom.codprod
|
||||
AND pctabpr.numregiao = pcprecoprom.numregiao
|
||||
AND pctabpr.codprod = pcprodut.codprod
|
||||
AND pcprodut.codmarca = pcmarca.codmarca (+)
|
||||
AND pcprecoprom.codplpagmax = pcplpag.codplpag (+)
|
||||
AND TRUNC(pcprecoprom.dtiniciovigencia) = TRUNC(TO_DATE(:0, 'DD/MM/YYYY'))
|
||||
AND pcprecoprom.codprod IN (${codprodPlaceholders.join(',')})
|
||||
AND PCPRECOPROM.DTFIMVIGENCIA >= TRUNC(SYSDATE)
|
||||
AND pcprecoprom.codplpagmax IN (42, 46)
|
||||
AND pctabpr.numregiao = :${paramIndex}
|
||||
`;
|
||||
|
||||
const result = await this.dataSource.query(sql, params);
|
||||
|
||||
return result.map((row) => ({
|
||||
codprod: row.CODPROD,
|
||||
descricao: row.DESCRICAO,
|
||||
marca: row.MARCA,
|
||||
unidade: row.UNIDADE,
|
||||
pvenda1: row.PVENDA1,
|
||||
precofixo: row.PRECOFIXO,
|
||||
percdesconto: row.PERCDESCONTO,
|
||||
dtfimvigencia: row.DTFIMVIGENCIA,
|
||||
mensagem2: row.MENSAGEM2,
|
||||
mensagem3: row.MENSAGEM3,
|
||||
mensagem4: row.MENSAGEM4,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user