fix: ajuste no endpoint de impressão de pedidos.
This commit is contained in:
58
.github/workflows/publish-sdk.yml
vendored
Normal file
58
.github/workflows/publish-sdk.yml
vendored
Normal 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
173
SDK_README.md
Normal 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
141
SDK_UPDATE_SUMMARY.md
Normal 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
|
||||||
|
|
||||||
@@ -17,7 +17,11 @@
|
|||||||
"test:watch": "jest --watch",
|
"test:watch": "jest --watch",
|
||||||
"test:cov": "jest --coverage",
|
"test:cov": "jest --coverage",
|
||||||
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
"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": {
|
"dependencies": {
|
||||||
"@nestjs/axios": "^4.0.0",
|
"@nestjs/axios": "^4.0.0",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { StoreDto } from './dto/store.dto';
|
|||||||
import { SellerDto } from './dto/seller.dto';
|
import { SellerDto } from './dto/seller.dto';
|
||||||
import { BillingDto } from './dto/billing.dto';
|
import { BillingDto } from './dto/billing.dto';
|
||||||
import { CustomerDto } from './dto/customer.dto';
|
import { CustomerDto } from './dto/customer.dto';
|
||||||
|
import { RegionDto } from './dto/region.dto';
|
||||||
import { CarrierDto, FindCarriersDto } from './dto/carrier.dto';
|
import { CarrierDto, FindCarriersDto } from './dto/carrier.dto';
|
||||||
|
|
||||||
@ApiTags('DataConsult')
|
@ApiTags('DataConsult')
|
||||||
@@ -103,4 +104,13 @@ export class DataConsultController {
|
|||||||
return this.dataConsultService.getOrderCarriers(orderId);
|
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 { BillingDto } from './dto/billing.dto';
|
||||||
import { CustomerDto } from './dto/customer.dto';
|
import { CustomerDto } from './dto/customer.dto';
|
||||||
import { ProductDto } from './dto/product.dto';
|
import { ProductDto } from './dto/product.dto';
|
||||||
|
import { RegionDto } from './dto/region.dto';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { DATA_SOURCE } from '../core/constants';
|
import { DATA_SOURCE } from '../core/constants';
|
||||||
|
|
||||||
@@ -217,4 +218,19 @@ async findSellers(): Promise<SellerDto[]> {
|
|||||||
`;
|
`;
|
||||||
return await this.executeQuery<any[]>(sql, [orderId]);
|
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 { BillingDto } from './dto/billing.dto';
|
||||||
import { CustomerDto } from './dto/customer.dto';
|
import { CustomerDto } from './dto/customer.dto';
|
||||||
import { ProductDto } from './dto/product.dto';
|
import { ProductDto } from './dto/product.dto';
|
||||||
|
import { RegionDto } from './dto/region.dto';
|
||||||
import { CarrierDto, FindCarriersDto } from './dto/carrier.dto';
|
import { CarrierDto, FindCarriersDto } from './dto/carrier.dto';
|
||||||
import { ILogger } from '../Log/ILogger';
|
import { ILogger } from '../Log/ILogger';
|
||||||
import { RedisClientToken } from '../core/configs/cache/redis-client.adapter.provider';
|
import { RedisClientToken } from '../core/configs/cache/redis-client.adapter.provider';
|
||||||
@@ -24,6 +25,8 @@ export class DataConsultService {
|
|||||||
private readonly CUSTOMERS_TTL = 3600;
|
private readonly CUSTOMERS_TTL = 3600;
|
||||||
private readonly CARRIERS_CACHE_KEY = 'data-consult:carriers:all';
|
private readonly CARRIERS_CACHE_KEY = 'data-consult:carriers:all';
|
||||||
private readonly CARRIERS_TTL = 3600;
|
private readonly CARRIERS_TTL = 3600;
|
||||||
|
private readonly REGIONS_CACHE_KEY = 'data-consult:regions';
|
||||||
|
private readonly REGIONS_TTL = 7200;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly repository: DataConsultRepository,
|
private readonly repository: DataConsultRepository,
|
||||||
@@ -205,4 +208,26 @@ export class DataConsultService {
|
|||||||
throw new HttpException('Erro ao buscar transportadoras do pedido', HttpStatus.INTERNAL_SERVER_ERROR);
|
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 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,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, 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')
|
//@ApiBearerAuth()
|
||||||
@Controller('api/v1/products')
|
//@UseGuards(JwtAuthGuard)
|
||||||
export class ProductsController {
|
@ApiTags('Produtos')
|
||||||
constructor(private readonly productsService: ProductsService) {}
|
@Controller('api/v1/products')
|
||||||
|
export class ProductsController {
|
||||||
///enpoit produtos-ecommecer
|
constructor(private readonly productsService: ProductsService) {}
|
||||||
@Get('products-ecommerce')
|
|
||||||
@ApiOperation({ summary: 'Lista produtos para o e-commerce' })
|
///enpoit produtos-ecommecer
|
||||||
@ApiResponse({
|
@Get('products-ecommerce')
|
||||||
status: 200,
|
@ApiOperation({ summary: 'Lista produtos para o e-commerce' })
|
||||||
description: 'Lista de produtos retornada com sucesso.',
|
@ApiResponse({
|
||||||
type: ProductEcommerceDto,
|
status: 200,
|
||||||
isArray: true
|
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)' })
|
///ENDPOIT DE VALIDAR PRODUTO POR FILTRO
|
||||||
@ApiParam({ name: 'storeId', type: String, description: 'ID da loja' })
|
@Get('product-validation/:storeId/:filtro')
|
||||||
@ApiParam({ name: 'filtro', type: String, description: 'Filtro de busca (código, EAN ou descrição)' })
|
@ApiOperation({ summary: 'Valida produto pelo filtro (código, EAN ou descrição)' })
|
||||||
@ApiResponse({
|
@ApiParam({ name: 'storeId', type: String, description: 'ID da loja' })
|
||||||
status: 200,
|
@ApiParam({ name: 'filtro', type: String, description: 'Filtro de busca (código, EAN ou descrição)' })
|
||||||
description: 'Produto encontrado com sucesso.',
|
@ApiResponse({
|
||||||
type: ProductValidationDto
|
status: 200,
|
||||||
})
|
description: 'Produto encontrado com sucesso.',
|
||||||
@ApiResponse({ status: 404, description: 'Produto não localizado.' })
|
type: ProductValidationDto
|
||||||
async productValidation(
|
})
|
||||||
@Param('storeId') storeId: string,
|
@ApiResponse({ status: 404, description: 'Produto não localizado.' })
|
||||||
@Param('filtro') filtro: string,
|
async productValidation(
|
||||||
): Promise<ProductValidationDto> {
|
@Param('storeId') storeId: string,
|
||||||
return this.productsService.productsValidation(storeId, filtro);
|
@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' })
|
/// ENDPOIT PRODUTOS EXPOSTOS
|
||||||
@ApiBody({ type: ExposedProductDto })
|
@Post('exposed-product')
|
||||||
@ApiResponse({ status: 201, description: 'Produto exposto registrado com sucesso.' })
|
@ApiOperation({ summary: 'Registra produto em exposição' })
|
||||||
async exposedProduct(@Body() exposedProduct: ExposedProduct) {
|
@ApiBody({ type: ExposedProductDto })
|
||||||
return this.productsService.exposedProduct(exposedProduct);
|
@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 { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||||
import { InjectDataSource } from '@nestjs/typeorm';
|
import { InjectDataSource } from '@nestjs/typeorm';
|
||||||
import { ExposedProduct } from 'src/core/models/exposed-product.model';
|
import { ExposedProduct } from 'src/core/models/exposed-product.model';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
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 { 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 {
|
@Injectable()
|
||||||
constructor(
|
export class ProductsService {
|
||||||
@InjectDataSource("oracle") private readonly dataSource: DataSource
|
constructor(
|
||||||
) {}
|
@InjectDataSource("oracle") private readonly dataSource: DataSource
|
||||||
|
) {}
|
||||||
async productsValidation(storeId: string, filtro: string): Promise<ProductValidationDto> {
|
|
||||||
const queryRunner = this.dataSource.createQueryRunner();
|
/**
|
||||||
await queryRunner.connect();
|
* Valida e busca informações de um produto por código ou descrição
|
||||||
|
* @param storeId - Código da filial
|
||||||
try {
|
* @param filtro - Filtro de busca (código auxiliar, código produto ou descrição)
|
||||||
const sql = `SELECT PCPRODUT.DESCRICAO as "descricao"
|
* @returns Dados do produto encontrado com estoque e preço
|
||||||
,PCPRODUT.CODPROD as "codigoProduto"
|
* @throws HttpException quando produto não é encontrado
|
||||||
,PCPRODUT.CODAUXILIAR as "codigoAuxiliar"
|
*/
|
||||||
,PCMARCA.MARCA as "marca"
|
async productsValidation(storeId: string, filtro: string): Promise<ProductValidationDto> {
|
||||||
,REPLACE(NVL(URLIMAGEM, 'http://10.1.1.191/si.png'), 'http://167.249.211.178:8001/', 'http://10.1.1.191/') as "images"
|
const sql = `SELECT PCPRODUT.DESCRICAO as "descricao"
|
||||||
,CASE WHEN PCPRODUT.TIPOPRODUTO = 'A' THEN 'AUTOSSERVICO'
|
,PCPRODUT.CODPROD as "codigoProduto"
|
||||||
WHEN PCPRODUT.TIPOPRODUTO = 'S' THEN 'SHOWROOM'
|
,PCPRODUT.CODAUXILIAR as "codigoAuxiliar"
|
||||||
WHEN PCPRODUT.TIPOPRODUTO = 'E' THEN 'ELETROMOVEIS'
|
,PCMARCA.MARCA as "marca"
|
||||||
ELSE 'OUTROS' END as "tipoProduto"
|
,REPLACE(NVL(URLIMAGEM, 'http://10.1.1.191/si.png'), 'http://167.249.211.178:8001/', 'http://10.1.1.191/') as "images"
|
||||||
,PCTABPR.PVENDA1 as "precoVenda"
|
,CASE WHEN PCPRODUT.TIPOPRODUTO = 'A' THEN 'AUTOSSERVICO'
|
||||||
,( PCEST.QTESTGER - PCEST.QTRESERV - PCEST.QTBLOQUEADA ) as "qtdeEstoqueLoja"
|
WHEN PCPRODUT.TIPOPRODUTO = 'S' THEN 'SHOWROOM'
|
||||||
,( SELECT ( ESTOQUE_CD.QTESTGER - ESTOQUE_CD.QTRESERV - ESTOQUE_CD.QTBLOQUEADA )
|
WHEN PCPRODUT.TIPOPRODUTO = 'E' THEN 'ELETROMOVEIS'
|
||||||
FROM PCEST ESTOQUE_CD
|
ELSE 'OUTROS' END as "tipoProduto"
|
||||||
WHERE ESTOQUE_CD.CODPROD = PCPRODUT.CODPROD
|
,PCTABPR.PVENDA1 as "precoVenda"
|
||||||
AND ESTOQUE_CD.CODFILIAL = 6 ) as "qtdeEstoqueCD"
|
,( PCEST.QTESTGER - PCEST.QTRESERV - PCEST.QTBLOQUEADA ) as "qtdeEstoqueLoja"
|
||||||
FROM PCPRODUT, PCEST, PCTABPR, PCMARCA
|
,( SELECT ( ESTOQUE_CD.QTESTGER - ESTOQUE_CD.QTRESERV - ESTOQUE_CD.QTBLOQUEADA )
|
||||||
WHERE PCPRODUT.CODPROD = PCEST.CODPROD
|
FROM PCEST ESTOQUE_CD
|
||||||
AND PCPRODUT.CODPROD = PCTABPR.CODPROD
|
WHERE ESTOQUE_CD.CODPROD = PCPRODUT.CODPROD
|
||||||
AND PCPRODUT.CODMARCA = PCMARCA.CODMARCA
|
AND ESTOQUE_CD.CODFILIAL = 6 ) as "qtdeEstoqueCD"
|
||||||
AND PCTABPR.NUMREGIAO = 1
|
FROM PCPRODUT, PCEST, PCTABPR, PCMARCA
|
||||||
AND PCEST.CODFILIAL = '${storeId}'
|
WHERE PCPRODUT.CODPROD = PCEST.CODPROD
|
||||||
AND ( PCPRODUT.CODAUXILIAR = REGEXP_REPLACE('${filtro}', '[^0-9]', '') OR
|
AND PCPRODUT.CODPROD = PCTABPR.CODPROD
|
||||||
PCPRODUT.CODPROD = REGEXP_REPLACE('${filtro}', '[^0-9]', '') OR
|
AND PCPRODUT.CODMARCA = PCMARCA.CODMARCA
|
||||||
PCPRODUT.DESCRICAO LIKE '%'||'${filtro}'||'%' )`;
|
AND PCTABPR.NUMREGIAO = 1
|
||||||
|
AND PCEST.CODFILIAL = :storeId
|
||||||
const products = await queryRunner.manager.query(sql);
|
AND ( PCPRODUT.CODAUXILIAR = REGEXP_REPLACE(:filtro1, '[^0-9]', '') OR
|
||||||
|
PCPRODUT.CODPROD = REGEXP_REPLACE(:filtro2, '[^0-9]', '') OR
|
||||||
if (products.length === 0) {
|
PCPRODUT.DESCRICAO LIKE '%'||:filtro3||'%' )`;
|
||||||
throw new HttpException('Produto não localizado!', HttpStatus.NOT_FOUND);
|
|
||||||
}
|
const products = await this.dataSource.query(sql, [storeId, filtro, filtro, filtro]);
|
||||||
|
|
||||||
const product = products[0];
|
if (products.length === 0) {
|
||||||
|
throw new HttpException('Produto não localizado!', HttpStatus.NOT_FOUND);
|
||||||
if (!product.images) {
|
}
|
||||||
product.images = [];
|
|
||||||
} else {
|
const product = products[0];
|
||||||
product.images = product.images.includes(';')
|
|
||||||
? product.images.split(';')
|
if (!product.images) {
|
||||||
: [product.images];
|
product.images = [];
|
||||||
}
|
} else {
|
||||||
|
product.images = product.images.includes(';')
|
||||||
return product;
|
? product.images.split(';')
|
||||||
} finally {
|
: [product.images];
|
||||||
await queryRunner.release();
|
}
|
||||||
}
|
|
||||||
}
|
return product;
|
||||||
|
}
|
||||||
async exposedProduct(product: ExposedProduct) {
|
|
||||||
const queryRunner = this.dataSource.createQueryRunner();
|
/**
|
||||||
await queryRunner.connect();
|
* Registra produto exposto em showroom
|
||||||
await queryRunner.startTransaction();
|
* @param product - Dados do produto exposto (storeId, ean, userId)
|
||||||
|
* @returns Mensagem de sucesso
|
||||||
try {
|
* @throws Lança exceção em caso de erro na transação
|
||||||
const sqlInsert = `INSERT INTO ESTPRODUTOEXPOSICAO ( CODFILIAL, DATA, CODAUXILIAR, CODFUNC )
|
*/
|
||||||
VALUES ( '${product.storeId}', TRUNC(SYSDATE), ${product.ean}, ${product.userId})`;
|
async exposedProduct(product: ExposedProduct) {
|
||||||
await queryRunner.query(sqlInsert);
|
const queryRunner = this.dataSource.createQueryRunner();
|
||||||
await queryRunner.commitTransaction();
|
await queryRunner.connect();
|
||||||
return { message: 'Registro incluído com sucesso!' };
|
await queryRunner.startTransaction();
|
||||||
} catch (err) {
|
|
||||||
await queryRunner.rollbackTransaction();
|
try {
|
||||||
throw err;
|
const sqlInsert = `INSERT INTO ESTPRODUTOEXPOSICAO ( CODFILIAL, DATA, CODAUXILIAR, CODFUNC )
|
||||||
} finally {
|
VALUES ( :storeId, TRUNC(SYSDATE), :ean, :userId )`;
|
||||||
await queryRunner.release();
|
await queryRunner.query(sqlInsert, [product.storeId, product.ean, product.userId]);
|
||||||
}
|
await queryRunner.commitTransaction();
|
||||||
}
|
return { message: 'Registro incluído com sucesso!' };
|
||||||
|
} catch (err) {
|
||||||
async getProductsEcommerce(): Promise<ProductEcommerceDto[]> {
|
await queryRunner.rollbackTransaction();
|
||||||
const queryRunner = this.dataSource.createQueryRunner();
|
throw err;
|
||||||
await queryRunner.connect();
|
} finally {
|
||||||
|
await queryRunner.release();
|
||||||
try {
|
}
|
||||||
const sql = `SELECT P.CODPROD as "productIdErp"
|
}
|
||||||
,P.VTEXSKUID as "productId"
|
|
||||||
,ROUND(P.PVENDA,2) as "price"
|
/**
|
||||||
,ROUND(P.PRECOKIT,2) as "priceKit"
|
* Busca produtos disponíveis para e-commerce
|
||||||
FROM ESVPRODUTOSECOMMERCE P
|
* @returns Lista de produtos com preços para e-commerce
|
||||||
WHERE P.VTEXSKUID > 0
|
*/
|
||||||
AND P.CODPROD IN (52057, 33702, 46410, 24518, 25816)`;
|
async getProductsEcommerce(): Promise<ProductEcommerceDto[]> {
|
||||||
|
const sql = `SELECT P.CODPROD as "productIdErp"
|
||||||
const products = await queryRunner.query(sql);
|
,P.VTEXSKUID as "productId"
|
||||||
return products;
|
,ROUND(P.PVENDA,2) as "price"
|
||||||
} finally {
|
,ROUND(P.PRECOKIT,2) as "priceKit"
|
||||||
await queryRunner.release();
|
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