fix: ajuste no endpoint de impressão de pedidos.
This commit is contained in:
@@ -7,6 +7,7 @@ import { StoreDto } from './dto/store.dto';
|
||||
import { SellerDto } from './dto/seller.dto';
|
||||
import { BillingDto } from './dto/billing.dto';
|
||||
import { CustomerDto } from './dto/customer.dto';
|
||||
import { RegionDto } from './dto/region.dto';
|
||||
import { CarrierDto, FindCarriersDto } from './dto/carrier.dto';
|
||||
|
||||
@ApiTags('DataConsult')
|
||||
@@ -103,4 +104,13 @@ export class DataConsultController {
|
||||
return this.dataConsultService.getOrderCarriers(orderId);
|
||||
}
|
||||
|
||||
@Get('regions')
|
||||
//@UseGuards(JwtAuthGuard)
|
||||
//@ApiBearerAuth()
|
||||
@ApiOperation({ summary: 'Lista todas as regiões cadastradas' })
|
||||
@ApiResponse({ status: 200, description: 'Lista de regiões retornada com sucesso', type: [RegionDto] })
|
||||
async getRegions(): Promise<RegionDto[]> {
|
||||
return this.dataConsultService.getRegions();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import { SellerDto } from './dto/seller.dto';
|
||||
import { BillingDto } from './dto/billing.dto';
|
||||
import { CustomerDto } from './dto/customer.dto';
|
||||
import { ProductDto } from './dto/product.dto';
|
||||
import { RegionDto } from './dto/region.dto';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { DATA_SOURCE } from '../core/constants';
|
||||
|
||||
@@ -217,4 +218,19 @@ async findSellers(): Promise<SellerDto[]> {
|
||||
`;
|
||||
return await this.executeQuery<any[]>(sql, [orderId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Busca todas as regiões cadastradas
|
||||
*/
|
||||
async findRegions(): Promise<RegionDto[]> {
|
||||
const sql = `
|
||||
SELECT
|
||||
PCREGIAO.NUMREGIAO as "numregiao",
|
||||
PCREGIAO.REGIAO as "regiao"
|
||||
FROM PCREGIAO
|
||||
ORDER BY PCREGIAO.NUMREGIAO
|
||||
`;
|
||||
const results = await this.executeQuery<RegionDto[]>(sql);
|
||||
return results.map(result => new RegionDto(result));
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import { SellerDto } from './dto/seller.dto';
|
||||
import { BillingDto } from './dto/billing.dto';
|
||||
import { CustomerDto } from './dto/customer.dto';
|
||||
import { ProductDto } from './dto/product.dto';
|
||||
import { RegionDto } from './dto/region.dto';
|
||||
import { CarrierDto, FindCarriersDto } from './dto/carrier.dto';
|
||||
import { ILogger } from '../Log/ILogger';
|
||||
import { RedisClientToken } from '../core/configs/cache/redis-client.adapter.provider';
|
||||
@@ -24,6 +25,8 @@ export class DataConsultService {
|
||||
private readonly CUSTOMERS_TTL = 3600;
|
||||
private readonly CARRIERS_CACHE_KEY = 'data-consult:carriers:all';
|
||||
private readonly CARRIERS_TTL = 3600;
|
||||
private readonly REGIONS_CACHE_KEY = 'data-consult:regions';
|
||||
private readonly REGIONS_TTL = 7200;
|
||||
|
||||
constructor(
|
||||
private readonly repository: DataConsultRepository,
|
||||
@@ -205,4 +208,26 @@ export class DataConsultService {
|
||||
throw new HttpException('Erro ao buscar transportadoras do pedido', HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obter todas as regiões cadastradas
|
||||
* @returns Array de RegionDto
|
||||
*/
|
||||
async getRegions(): Promise<RegionDto[]> {
|
||||
this.logger.log('Buscando todas as regiões');
|
||||
try {
|
||||
return getOrSetCache<RegionDto[]>(
|
||||
this.redisClient,
|
||||
this.REGIONS_CACHE_KEY,
|
||||
this.REGIONS_TTL,
|
||||
async () => {
|
||||
const regions = await this.repository.findRegions();
|
||||
return regions;
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.error('Erro ao buscar regiões', error);
|
||||
throw new HttpException('Erro ao buscar regiões', HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
23
src/data-consult/dto/region.dto.ts
Normal file
23
src/data-consult/dto/region.dto.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
/**
|
||||
* DTO para dados de região
|
||||
*/
|
||||
export class RegionDto {
|
||||
@ApiProperty({
|
||||
description: 'Código da região',
|
||||
example: 1,
|
||||
})
|
||||
numregiao: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Nome/descrição da região',
|
||||
example: 'REGIÃO SUL',
|
||||
})
|
||||
regiao: string;
|
||||
|
||||
constructor(partial: Partial<RegionDto>) {
|
||||
Object.assign(this, partial);
|
||||
}
|
||||
}
|
||||
|
||||
84
src/orders/dto/DebDto.ts
Normal file
84
src/orders/dto/DebDto.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
/**
|
||||
* DTO para dados de débitos/prestações de clientes
|
||||
*/
|
||||
export class DebDto {
|
||||
@ApiProperty({
|
||||
description: 'Data de emissão da prestação',
|
||||
example: '2024-01-15',
|
||||
type: Date,
|
||||
})
|
||||
dtemissao: Date;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Código da filial',
|
||||
example: '1',
|
||||
})
|
||||
codfilial: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Número da duplicata',
|
||||
example: '12345',
|
||||
})
|
||||
duplic: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Número da prestação',
|
||||
example: '1',
|
||||
})
|
||||
prest: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Código do cliente',
|
||||
example: 1000,
|
||||
})
|
||||
codcli: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Nome do cliente',
|
||||
example: 'JOÃO DA SILVA',
|
||||
})
|
||||
cliente: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Código de cobrança',
|
||||
example: 'BL',
|
||||
})
|
||||
codcob: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Descrição da forma de cobrança',
|
||||
example: 'BOLETO',
|
||||
})
|
||||
cobranca: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Data de vencimento',
|
||||
example: '2024-02-15',
|
||||
type: Date,
|
||||
})
|
||||
dtvenc: Date;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Data de pagamento',
|
||||
example: '2024-02-10',
|
||||
type: Date,
|
||||
nullable: true,
|
||||
})
|
||||
dtpag: Date | null;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Valor da prestação',
|
||||
example: 150.50,
|
||||
})
|
||||
valor: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Situação da prestação',
|
||||
example: 'PAGO',
|
||||
enum: ['PAGO', 'EM ATRASO', 'A VENCER', 'NENHUM'],
|
||||
})
|
||||
situacao: string;
|
||||
}
|
||||
|
||||
33
src/products/dto/product-detail-query.dto.ts
Normal file
33
src/products/dto/product-detail-query.dto.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsArray, IsNotEmpty, IsNumber, IsString } from 'class-validator';
|
||||
|
||||
/**
|
||||
* DTO para requisição de detalhes de produtos
|
||||
*/
|
||||
export class ProductDetailQueryDto {
|
||||
@ApiProperty({
|
||||
description: 'Código da região para buscar o preço',
|
||||
example: 1,
|
||||
})
|
||||
@IsNumber()
|
||||
@IsNotEmpty()
|
||||
numregiao: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Array de códigos de produtos',
|
||||
example: [1, 2, 3],
|
||||
type: [Number],
|
||||
})
|
||||
@IsArray()
|
||||
@IsNotEmpty()
|
||||
codprod: number[];
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Código da filial',
|
||||
example: '1',
|
||||
})
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
codfilial: string;
|
||||
}
|
||||
|
||||
55
src/products/dto/product-detail-response.dto.ts
Normal file
55
src/products/dto/product-detail-response.dto.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
/**
|
||||
* DTO para resposta de detalhes de produtos
|
||||
*/
|
||||
export class ProductDetailResponseDto {
|
||||
@ApiProperty({
|
||||
description: 'Código do produto',
|
||||
example: 12345,
|
||||
})
|
||||
codprod: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Descrição completa do produto (com marca)',
|
||||
example: 'PRODUTO EXEMPLO - MARCA EXEMPLO',
|
||||
})
|
||||
descricao: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Tipo de embalagem',
|
||||
example: 'UN',
|
||||
})
|
||||
embalagem: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Código auxiliar (código de barras)',
|
||||
example: '7891234567890',
|
||||
})
|
||||
codauxiliar: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Nome da marca',
|
||||
example: 'MARCA EXEMPLO',
|
||||
})
|
||||
marca: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Preço de venda do produto',
|
||||
example: 99.90,
|
||||
})
|
||||
preco: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Nome da filial',
|
||||
example: 'FILIAL MATRIZ',
|
||||
})
|
||||
filial: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Nome da região',
|
||||
example: 'REGIÃO SUL',
|
||||
})
|
||||
regiao: string;
|
||||
}
|
||||
|
||||
@@ -1,59 +1,78 @@
|
||||
/* eslint-disable prettier/prettier */
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
|
||||
import { Body, Controller, Get, Param, Post,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';
|
||||
|
||||
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ApiTags('Produtos')
|
||||
@Controller('api/v1/products')
|
||||
export class ProductsController {
|
||||
constructor(private readonly productsService: ProductsService) {}
|
||||
|
||||
///enpoit produtos-ecommecer
|
||||
@Get('products-ecommerce')
|
||||
@ApiOperation({ summary: 'Lista produtos para o e-commerce' })
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Lista de produtos retornada com sucesso.',
|
||||
type: ProductEcommerceDto,
|
||||
isArray: true
|
||||
})
|
||||
|
||||
///ENDPOIT DE VALIDAR PRODUTO POR FILTRO
|
||||
@Get('product-validation/:storeId/:filtro')
|
||||
@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)' })
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Produto encontrado com sucesso.',
|
||||
type: ProductValidationDto
|
||||
})
|
||||
@ApiResponse({ status: 404, description: 'Produto não localizado.' })
|
||||
async productValidation(
|
||||
@Param('storeId') storeId: string,
|
||||
@Param('filtro') filtro: string,
|
||||
): Promise<ProductValidationDto> {
|
||||
return this.productsService.productsValidation(storeId, filtro);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// ENDPOIT PRODUTOS EXPOSTOS
|
||||
@Post('exposed-product')
|
||||
@ApiOperation({ summary: 'Registra produto em exposição' })
|
||||
@ApiBody({ type: ExposedProductDto })
|
||||
@ApiResponse({ status: 201, description: 'Produto exposto registrado com sucesso.' })
|
||||
async exposedProduct(@Body() exposedProduct: ExposedProduct) {
|
||||
return this.productsService.exposedProduct(exposedProduct);
|
||||
}
|
||||
}
|
||||
/* eslint-disable prettier/prettier */
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
|
||||
import { Body, Controller, Get, Param, Post,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 { ProductDetailQueryDto } from './dto/product-detail-query.dto';
|
||||
import { ProductDetailResponseDto } from './dto/product-detail-response.dto';
|
||||
|
||||
|
||||
//@ApiBearerAuth()
|
||||
//@UseGuards(JwtAuthGuard)
|
||||
@ApiTags('Produtos')
|
||||
@Controller('api/v1/products')
|
||||
export class ProductsController {
|
||||
constructor(private readonly productsService: ProductsService) {}
|
||||
|
||||
///enpoit produtos-ecommecer
|
||||
@Get('products-ecommerce')
|
||||
@ApiOperation({ summary: 'Lista produtos para o e-commerce' })
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Lista de produtos retornada com sucesso.',
|
||||
type: ProductEcommerceDto,
|
||||
isArray: true
|
||||
})
|
||||
|
||||
///ENDPOIT DE VALIDAR PRODUTO POR FILTRO
|
||||
@Get('product-validation/:storeId/:filtro')
|
||||
@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)' })
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Produto encontrado com sucesso.',
|
||||
type: ProductValidationDto
|
||||
})
|
||||
@ApiResponse({ status: 404, description: 'Produto não localizado.' })
|
||||
async productValidation(
|
||||
@Param('storeId') storeId: string,
|
||||
@Param('filtro') filtro: string,
|
||||
): Promise<ProductValidationDto> {
|
||||
return this.productsService.productsValidation(storeId, filtro);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// ENDPOIT PRODUTOS EXPOSTOS
|
||||
@Post('exposed-product')
|
||||
@ApiOperation({ summary: 'Registra produto em exposição' })
|
||||
@ApiBody({ type: ExposedProductDto })
|
||||
@ApiResponse({ status: 201, description: 'Produto exposto registrado com sucesso.' })
|
||||
async exposedProduct(@Body() exposedProduct: ExposedProduct) {
|
||||
return this.productsService.exposedProduct(exposedProduct);
|
||||
}
|
||||
|
||||
/**
|
||||
* Endpoint para buscar detalhes de produtos com preço e estoque
|
||||
*/
|
||||
@Post('product-details')
|
||||
@ApiOperation({ summary: 'Busca detalhes de produtos com preço e estoque' })
|
||||
@ApiBody({ type: ProductDetailQueryDto })
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Lista de produtos com detalhes retornada com sucesso.',
|
||||
type: ProductDetailResponseDto,
|
||||
isArray: true
|
||||
})
|
||||
@ApiResponse({ status: 400, description: 'Parâmetros inválidos.' })
|
||||
async getProductDetails(@Body() query: ProductDetailQueryDto): Promise<ProductDetailResponseDto[]> {
|
||||
return this.productsService.getProductDetails(query);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,105 +1,146 @@
|
||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||
import { InjectDataSource } from '@nestjs/typeorm';
|
||||
import { ExposedProduct } from 'src/core/models/exposed-product.model';
|
||||
import { DataSource } from 'typeorm';
|
||||
import { ProductValidationDto } from './dto/ProductValidationDto';
|
||||
import { ProductEcommerceDto } from './dto/product-ecommerce.dto';
|
||||
import { ResultModel } from 'src/shared/ResultModel';
|
||||
|
||||
@Injectable()
|
||||
export class ProductsService {
|
||||
constructor(
|
||||
@InjectDataSource("oracle") private readonly dataSource: DataSource
|
||||
) {}
|
||||
|
||||
async productsValidation(storeId: string, filtro: string): Promise<ProductValidationDto> {
|
||||
const queryRunner = this.dataSource.createQueryRunner();
|
||||
await queryRunner.connect();
|
||||
|
||||
try {
|
||||
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('${filtro}', '[^0-9]', '') OR
|
||||
PCPRODUT.CODPROD = REGEXP_REPLACE('${filtro}', '[^0-9]', '') OR
|
||||
PCPRODUT.DESCRICAO LIKE '%'||'${filtro}'||'%' )`;
|
||||
|
||||
const products = await queryRunner.manager.query(sql);
|
||||
|
||||
if (products.length === 0) {
|
||||
throw new HttpException('Produto não localizado!', HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
const product = products[0];
|
||||
|
||||
if (!product.images) {
|
||||
product.images = [];
|
||||
} else {
|
||||
product.images = product.images.includes(';')
|
||||
? product.images.split(';')
|
||||
: [product.images];
|
||||
}
|
||||
|
||||
return product;
|
||||
} finally {
|
||||
await queryRunner.release();
|
||||
}
|
||||
}
|
||||
|
||||
async exposedProduct(product: ExposedProduct) {
|
||||
const queryRunner = this.dataSource.createQueryRunner();
|
||||
await queryRunner.connect();
|
||||
await queryRunner.startTransaction();
|
||||
|
||||
try {
|
||||
const sqlInsert = `INSERT INTO ESTPRODUTOEXPOSICAO ( CODFILIAL, DATA, CODAUXILIAR, CODFUNC )
|
||||
VALUES ( '${product.storeId}', TRUNC(SYSDATE), ${product.ean}, ${product.userId})`;
|
||||
await queryRunner.query(sqlInsert);
|
||||
await queryRunner.commitTransaction();
|
||||
return { message: 'Registro incluído com sucesso!' };
|
||||
} catch (err) {
|
||||
await queryRunner.rollbackTransaction();
|
||||
throw err;
|
||||
} finally {
|
||||
await queryRunner.release();
|
||||
}
|
||||
}
|
||||
|
||||
async getProductsEcommerce(): Promise<ProductEcommerceDto[]> {
|
||||
const queryRunner = this.dataSource.createQueryRunner();
|
||||
await queryRunner.connect();
|
||||
|
||||
try {
|
||||
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 queryRunner.query(sql);
|
||||
return products;
|
||||
} finally {
|
||||
await queryRunner.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||
import { InjectDataSource } from '@nestjs/typeorm';
|
||||
import { ExposedProduct } from 'src/core/models/exposed-product.model';
|
||||
import { DataSource } from 'typeorm';
|
||||
import { ProductValidationDto } from './dto/ProductValidationDto';
|
||||
import { ProductEcommerceDto } from './dto/product-ecommerce.dto';
|
||||
import { ProductDetailQueryDto } from './dto/product-detail-query.dto';
|
||||
import { ProductDetailResponseDto } from './dto/product-detail-response.dto';
|
||||
|
||||
@Injectable()
|
||||
export class ProductsService {
|
||||
constructor(
|
||||
@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
|
||||
*/
|
||||
async productsValidation(storeId: string, filtro: string): Promise<ProductValidationDto> {
|
||||
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 products = await this.dataSource.query(sql, [storeId, filtro, filtro, filtro]);
|
||||
|
||||
if (products.length === 0) {
|
||||
throw new HttpException('Produto não localizado!', HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
const product = products[0];
|
||||
|
||||
if (!product.images) {
|
||||
product.images = [];
|
||||
} else {
|
||||
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();
|
||||
await queryRunner.startTransaction();
|
||||
|
||||
try {
|
||||
const sqlInsert = `INSERT INTO ESTPRODUTOEXPOSICAO ( CODFILIAL, DATA, CODAUXILIAR, CODFUNC )
|
||||
VALUES ( :storeId, TRUNC(SYSDATE), :ean, :userId )`;
|
||||
await queryRunner.query(sqlInsert, [product.storeId, product.ean, product.userId]);
|
||||
await queryRunner.commitTransaction();
|
||||
return { message: 'Registro incluído com sucesso!' };
|
||||
} catch (err) {
|
||||
await queryRunner.rollbackTransaction();
|
||||
throw err;
|
||||
} finally {
|
||||
await queryRunner.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Busca produtos disponíveis para e-commerce
|
||||
* @returns Lista de produtos com preços para e-commerce
|
||||
*/
|
||||
async getProductsEcommerce(): Promise<ProductEcommerceDto[]> {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
async getProductDetails(query: ProductDetailQueryDto): Promise<ProductDetailResponseDto[]> {
|
||||
const { numregiao, codprod, codfilial } = query;
|
||||
|
||||
const placeholders = codprod.map((_, index) => `:codprod${index}`).join(',');
|
||||
|
||||
const sql = `
|
||||
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
|
||||
WHERE PCTABPR.CODPROD = PCPRODUT.CODPROD
|
||||
AND PCTABPR.NUMREGIAO = :numregiao1) AS "preco",
|
||||
(SELECT FANTASIA
|
||||
FROM PCFILIAL F
|
||||
WHERE CODIGO = :codfilial) AS "filial",
|
||||
(SELECT REGIAO
|
||||
FROM PCREGIAO
|
||||
WHERE NUMREGIAO = :numregiao2) AS "regiao"
|
||||
FROM PCPRODUT
|
||||
LEFT JOIN PCMARCA ON PCPRODUT.CODMARCA = PCMARCA.CODMARCA
|
||||
WHERE PCPRODUT.CODPROD IN (${placeholders})
|
||||
`;
|
||||
|
||||
const params = [numregiao, codfilial, numregiao, ...codprod];
|
||||
const products = await this.dataSource.query(sql, params);
|
||||
return products;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user