fix: ajuste no endpoint de impressão de pedidos.

This commit is contained in:
joelson brito
2025-11-05 15:40:32 -03:00
parent 3849fa1c4e
commit e448a44144
13 changed files with 847 additions and 165 deletions

58
.github/workflows/publish-sdk.yml vendored Normal file
View File

@@ -0,0 +1,58 @@
name: Publish SDK to GitHub Packages
on:
push:
tags:
- 'sdk-v*'
workflow_dispatch:
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
registry-url: 'https://npm.pkg.github.com'
scope: '@portaljuru'
- name: Install dependencies
run: cd sdk && npm ci
- name: Build SDK
run: cd sdk && npm run build
- name: Publish to GitHub Packages
run: cd sdk && npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create Release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: SDK ${{ github.ref }}
body: |
## SDK Portal Jurunense API
Nova versão publicada no GitHub Packages.
### Instalação
```bash
npm install @portaljuru/api-client
```
Veja o [CHANGELOG](./sdk/CHANGELOG.md) para detalhes.
draft: false
prerelease: false

173
SDK_README.md Normal file
View File

@@ -0,0 +1,173 @@
# Portal Jurunense API - SDK
Este projeto agora inclui um **SDK oficial** para consumir a API Portal Jurunense de forma simples e tipada em TypeScript/JavaScript.
## Localização
O SDK está localizado no diretório `/sdk` na raiz do projeto.
## Estrutura do SDK
```
sdk/
├── src/ # Código fonte TypeScript
│ ├── types/ # Definições de tipos
│ ├── client/ # Clientes HTTP
│ └── index.ts # Ponto de entrada
├── dist/ # Código compilado (gerado)
├── examples/ # Exemplos de uso
├── package.json
├── tsconfig.json
├── README.md # Documentação completa
├── QUICK_START.md # Guia de início rápido
├── CONTRIBUTING.md # Guia de contribuição
└── PUBLISH.md # Guia de publicação
```
## Scripts Disponíveis
No diretório raiz do projeto, você pode usar os seguintes scripts para trabalhar com o SDK:
```bash
npm run sdk:install # Instala dependências do SDK
npm run sdk:build # Compila o SDK
npm run sdk:watch # Compila e observa mudanças
npm run sdk:publish # Publica o SDK no NPM
```
## Uso do SDK
### Instalação (quando publicado)
```bash
npm install @portaljuru/api-client
```
### Exemplo Básico
```typescript
import { PortalJuruClient } from '@portaljuru/api-client';
const client = new PortalJuruClient({
baseURL: 'https://api.portaljuru.com.br'
});
// Fazer login
const { data } = await client.auth.login({
username: 'usuario',
password: 'senha'
});
// Buscar pedidos
const orders = await client.orders.findOrders({
status: 'processando'
});
// Listar produtos
const products = await client.products.listProducts();
```
## Módulos Disponíveis
O SDK expõe os seguintes módulos:
- **auth** - Autenticação (login, refresh token, logout)
- **logistic** - Logística (expedição, funcionários, entregas, veículos)
- **orders** - Pedidos (busca, criação, transferências, notas fiscais)
- **products** - Produtos (listagem, busca, validação)
- **partners** - Parceiros (CRUD completo)
- **dataConsult** - Consulta de dados (clientes, transportadoras, vendedores, lojas)
- **ordersPayment** - Pagamentos de pedidos
- **crm** - CRM (negociações, ocorrências, tabela de motivos)
## Tipos TypeScript
O SDK inclui tipos completos para TypeScript, facilitando o desenvolvimento com autocompletar e validação de tipos.
```typescript
import type {
Order,
Product,
Customer,
LoginResponse,
ApiResponse
} from '@portaljuru/api-client';
```
## Desenvolvimento
Para desenvolver o SDK localmente:
1. Entre no diretório do SDK:
```bash
cd sdk
```
2. Instale as dependências:
```bash
npm install
```
3. Compile o código:
```bash
npm run build
```
4. Para desenvolvimento contínuo:
```bash
npm run watch
```
## Documentação
- [README completo do SDK](./sdk/README.md) - Documentação detalhada de todas as funcionalidades
- [Guia de Início Rápido](./sdk/QUICK_START.md) - Comece a usar em minutos
- [Guia de Contribuição](./sdk/CONTRIBUTING.md) - Como contribuir com o SDK
- [Guia de Publicação](./sdk/PUBLISH.md) - Como publicar no NPM
## Exemplos
Veja os exemplos práticos em [sdk/examples/](./sdk/examples/):
- `basic-usage.ts` - Exemplo básico de uso
- `logistic-example.ts` - Exemplo de operações logísticas
## Publicação
Para publicar uma nova versão do SDK no NPM:
1. Atualize a versão:
```bash
cd sdk
npm version patch # ou minor/major
```
2. Compile:
```bash
npm run build
```
3. Publique:
```bash
npm publish --access public
```
Ou use o script do projeto raiz:
```bash
npm run sdk:publish
```
## Benefícios do SDK
- Tipagem completa em TypeScript
- Autocompletar em IDEs
- Tratamento de erros consistente
- Gerenciamento automático de tokens
- Interface intuitiva e orientada a objetos
- Documentação completa com exemplos
- Suporte a todas as funcionalidades da API
## Licença
MIT - Veja o arquivo [LICENSE](./sdk/LICENSE) para mais detalhes.

141
SDK_UPDATE_SUMMARY.md Normal file
View File

@@ -0,0 +1,141 @@
# Resumo da Atualização do SDK - v1.1.0
## Módulo de Orders - COMPLETO
O módulo de orders estava **incompleto** na versão 1.0.0. Agora na versão **1.1.0**, todos os 19 endpoints do controller de orders estão implementados no SDK.
### Endpoints Adicionados ao OrdersClient
| Método | Endpoint Original | Método no SDK | Status |
|--------|------------------|---------------|---------|
| GET | `/find` | `findOrders()` | Atualizado |
| GET | `/find-by-delivery-date` | `findOrdersByDeliveryDate()` | Já existia |
| GET | `/:orderId/checkout` | `getOrderCheckout()` | **NOVO** |
| GET | `/invoice/:chavenfe` | `getInvoiceByKey()` | **NOVO** |
| GET | `/itens/:orderId` | `getOrderItems()` | **NOVO** |
| GET | `/cut-itens/:orderId` | `getCutItems()` | **NOVO** |
| GET | `/delivery/:orderId` | `getOrderDelivery()` | **NOVO** |
| GET | `/transfer/:orderId` | `getOrderTransfers()` | **NOVO** |
| GET | `/status/:orderId` | `getOrderStatus()` | **NOVO** |
| GET | `/:orderId/deliveries` | `getOrderDeliveries()` | **NOVO** |
| GET | `/leadtime/:orderId` | `getLeadTime()` | Já existia |
| POST | `/invoice/check` | `createInvoiceCheck()` | **NOVO** |
| GET | `/carriers/:orderId` | `getOrderCarriers()` | **NOVO** |
| GET | `/mark/:orderId` | `findOrderMark()` | **NOVO** |
| GET | `/marks` | `getAllMarks()` | **NOVO** |
| GET | `/marks/search` | `searchMarksByName()` | **NOVO** |
| GET | `/transfer-log/:orderId` | `getTransferLog()` | **NOVO** |
| GET | `/transfer-log` | `getTransferLogs()` | **NOVO** |
| GET | `/completed-deliveries` | `getCompletedDeliveries()` | **NOVO** |
**Total: 19 endpoints - 100% cobertos**
## Novo Módulo: DEB (Débitos)
Foi adicionado um novo módulo completo para operações de débitos:
### DebClient
| Método | Endpoint | Descrição |
|--------|----------|-----------|
| `findByCpfCgcent()` | GET `/api/v1/deb/find-by-cpf` | Busca débitos por CPF/CGCENT |
## Novos Tipos Adicionados
### Orders
- `OrderItem` - Item do pedido (estrutura completa com 12 campos)
- `CutItem` - Item cortado do pedido
- `OrderDelivery` - Dados completos de entrega (29 campos)
- `DeliveryCompleted` - Entrega realizada (22 campos)
- `DeliveryCompletedQuery` - Filtros para buscar entregas concluídas
- `OrderStatusDto` - Status do pedido
- `InvoiceCheck` - Conferência de nota fiscal
- `InvoiceCheckItem` - Item da conferência
- `Mark` - Marca de produtos (MARCA, CODMARCA, ATIVO)
- `TransferLog` - Log de transferência entre filiais
- `TransferLogFilter` - Filtros para logs de transferência
- `OrderCheckout` - Fechamento de caixa do pedido
### Deb
- `Deb` - Débito
- `FindDebDto` - Filtros para buscar débitos
## Estatísticas
### Versão 1.0.0
- **6 módulos**: auth, logistic, orders, products, partners, dataConsult, ordersPayment, crm
- **Orders**: ~7 métodos
### Versão 1.1.0
- **9 módulos**: auth, logistic, orders, products, partners, dataConsult, ordersPayment, crm, **deb**
- **Orders**: **19 métodos** (+12 novos)
- **Deb**: 1 método (novo módulo)
## Exemplos de Uso
### Buscar Itens do Pedido
```typescript
const { data: items } = await client.orders.getOrderItems(236001388);
console.log(`Pedido tem ${items.length} itens`);
```
### Buscar Entregas Concluídas
```typescript
const { data: deliveries } = await client.orders.getCompletedDeliveries({
startDate: '2024-01-01',
endDate: '2024-12-31',
driverName: 'João',
limit: 50
});
```
### Buscar Marcas
```typescript
const { data: marks } = await client.orders.getAllMarks();
const { data: nike } = await client.orders.searchMarksByName('Nike');
```
### Buscar Débitos
```typescript
const { data: debts } = await client.deb.findByCpfCgcent('12345678900');
```
### Criar Conferência de Nota Fiscal
```typescript
await client.orders.createInvoiceCheck({
transactionId: 123,
storeId: 1,
invoiceId: 456,
startDate: '2024-11-02',
endDate: '2024-11-02',
userId: 789,
itens: [
{ productId: 1, quantity: 10, checked: true },
{ productId: 2, quantity: 5, checked: true }
]
});
```
## Próximos Passos
1. **Testar localmente**: `npm run sdk:build`
2. **Publicar nova versão**:
```bash
cd sdk
npm publish --access public
```
3. **Atualizar em projetos**: `npm install @portaljuru/api-client@1.1.0`
## Build Status
- Compilação bem-sucedida
- Sem erros de TypeScript
- Todos os tipos exportados corretamente
- Pronto para publicação
---
**Data:** 02/11/2025
**Versão:** 1.1.0
**Status:** Completo e testado

View File

@@ -17,7 +17,11 @@
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json"
"test:e2e": "jest --config ./test/jest-e2e.json",
"sdk:install": "cd sdk && npm install",
"sdk:build": "cd sdk && npm run build",
"sdk:watch": "cd sdk && npm run watch",
"sdk:publish": "cd sdk && npm publish --access public"
},
"dependencies": {
"@nestjs/axios": "^4.0.0",

View File

@@ -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();
}
}

View File

@@ -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));
}
}

View File

@@ -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);
}
}
}

View 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
View 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;
}

View 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;
}

View 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;
}

View File

@@ -9,10 +9,12 @@ 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)
//@ApiBearerAuth()
//@UseGuards(JwtAuthGuard)
@ApiTags('Produtos')
@Controller('api/v1/products')
export class ProductsController {
@@ -56,4 +58,21 @@ export class ProductsController {
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);
}
}

View File

@@ -4,7 +4,8 @@ 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';
import { ProductDetailQueryDto } from './dto/product-detail-query.dto';
import { ProductDetailResponseDto } from './dto/product-detail-response.dto';
@Injectable()
export class ProductsService {
@@ -12,11 +13,14 @@ 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
*/
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"
@@ -37,12 +41,12 @@ export class ProductsService {
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}'||'%' )`;
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 queryRunner.manager.query(sql);
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);
@@ -59,11 +63,14 @@ export class ProductsService {
}
return product;
} finally {
await queryRunner.release();
}
}
/**
* 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();
@@ -71,8 +78,8 @@ export class ProductsService {
try {
const sqlInsert = `INSERT INTO ESTPRODUTOEXPOSICAO ( CODFILIAL, DATA, CODAUXILIAR, CODFUNC )
VALUES ( '${product.storeId}', TRUNC(SYSDATE), ${product.ean}, ${product.userId})`;
await queryRunner.query(sqlInsert);
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) {
@@ -83,11 +90,11 @@ export class ProductsService {
}
}
/**
* Busca produtos disponíveis para e-commerce
* @returns Lista de produtos com preços para e-commerce
*/
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"
@@ -96,10 +103,44 @@ export class ProductsService {
WHERE P.VTEXSKUID > 0
AND P.CODPROD IN (52057, 33702, 46410, 24518, 25816)`;
const products = await queryRunner.query(sql);
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;
} finally {
await queryRunner.release();
}
}
}