feat: suporte a múltiplos sellerId e melhorias no código
- Adicionado suporte para sellerId como string separada por vírgula (ex: 270,431) - Melhorias em deb.repository: tipagem e documentação - Melhorias em deb.service: remoção de validação redundante - Melhorias em deb.controller: remoção de try/catch duplicado - Melhorias em orders.service: early returns e tipagem melhorada - Aplicado early returns para reduzir aninhamento - Melhorias de tipagem em todos os métodos
This commit is contained in:
@@ -1,34 +1,26 @@
|
||||
|
||||
import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { DebRepository } from '../repositories/deb.repository';
|
||||
import { DebDto } from '../dto/DebDto';
|
||||
|
||||
@Injectable()
|
||||
export class DebService {
|
||||
constructor(
|
||||
private readonly debRepository: DebRepository,
|
||||
) {}
|
||||
constructor(
|
||||
private readonly debRepository: DebRepository,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Busca débitos por CPF ou CGCENT
|
||||
* @param cpfCgcent - CPF ou CGCENT do cliente
|
||||
* @param matricula - Matrícula do funcionário (opcional)
|
||||
* @param cobranca - Código de cobrança (opcional)
|
||||
* @returns Lista de débitos do cliente
|
||||
*/
|
||||
async findByCpfCgcent(cpfCgcent: string, matricula?: number, cobranca?: string): Promise<DebDto[]> {
|
||||
if (!cpfCgcent) {
|
||||
throw new HttpException('CPF/CGCENT é obrigatório', HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await this.debRepository.findByCpfCgcent(cpfCgcent, matricula, cobranca);
|
||||
return result as DebDto[];
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Erro ao buscar débitos',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Busca débitos por CPF ou CGCENT
|
||||
* @param cpfCgcent - CPF ou CGCENT do cliente (validado pelo DTO)
|
||||
* @param matricula - Matrícula do funcionário (opcional)
|
||||
* @param cobranca - Código de cobrança (opcional)
|
||||
* @returns Lista de débitos do cliente
|
||||
* @throws {Error} Erro ao buscar débitos no banco de dados
|
||||
*/
|
||||
async findByCpfCgcent(
|
||||
cpfCgcent: string,
|
||||
matricula?: number,
|
||||
cobranca?: string,
|
||||
): Promise<DebDto[]> {
|
||||
return await this.debRepository.findByCpfCgcent(cpfCgcent, matricula, cobranca);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Injectable, Inject, HttpStatus } from '@nestjs/common';
|
||||
import { FindOrdersDto } from '../dto/find-orders.dto';
|
||||
import { FindOrdersByDeliveryDateDto } from '../dto/find-orders-by-delivery-date.dto';
|
||||
import { InvoiceDto } from '../dto/find-invoice.dto';
|
||||
import { CutItemDto } from '../dto/CutItemDto';
|
||||
import { OrdersRepository } from '../repositories/orders.repository';
|
||||
@@ -19,20 +20,22 @@ import { MarkData } from '../interface/markdata';
|
||||
import { EstLogTransferFilterDto, EstLogTransferResponseDto } from '../dto/estlogtransfer.dto';
|
||||
import { DeliveryCompletedQuery } from '../dto/delivery-completed-query.dto';
|
||||
import { DeliveryCompleted } from '../dto/delivery-completed.dto';
|
||||
|
||||
import { OrderResponseDto } from '../dto/order-response.dto';
|
||||
|
||||
@Injectable()
|
||||
export class OrdersService {
|
||||
private readonly TTL_ORDERS = 60; // 60 segundos
|
||||
private readonly TTL_INVOICE = 60; // 60 segundos
|
||||
private readonly TTL_ITENS = 60; // 60 segundos
|
||||
private readonly TTL_LEADTIME = 60; // 60 segundos
|
||||
private readonly TTL_DELIVERIES = 60; // 60 segundos
|
||||
private readonly TTL_TRANSFER = 60; // 60 segundos
|
||||
private readonly TTL_STATUS = 60; // 60 segundos
|
||||
private readonly TTL_CARRIERS = 60; // 60 segundos
|
||||
private readonly TTL_MARKS = 60; // 60 segundos
|
||||
private readonly TTL_COMPLETED_DELIVERIES = 60; // 60 segundos
|
||||
// Cache TTL em segundos
|
||||
private static readonly DEFAULT_TTL = 60;
|
||||
private readonly TTL_ORDERS = OrdersService.DEFAULT_TTL;
|
||||
private readonly TTL_INVOICE = OrdersService.DEFAULT_TTL;
|
||||
private readonly TTL_ITENS = OrdersService.DEFAULT_TTL;
|
||||
private readonly TTL_LEADTIME = OrdersService.DEFAULT_TTL;
|
||||
private readonly TTL_DELIVERIES = OrdersService.DEFAULT_TTL;
|
||||
private readonly TTL_TRANSFER = OrdersService.DEFAULT_TTL;
|
||||
private readonly TTL_STATUS = OrdersService.DEFAULT_TTL;
|
||||
private readonly TTL_CARRIERS = OrdersService.DEFAULT_TTL;
|
||||
private readonly TTL_MARKS = OrdersService.DEFAULT_TTL;
|
||||
private readonly TTL_COMPLETED_DELIVERIES = OrdersService.DEFAULT_TTL;
|
||||
|
||||
constructor(
|
||||
private readonly ordersRepository: OrdersRepository,
|
||||
@@ -41,8 +44,10 @@ export class OrdersService {
|
||||
|
||||
/**
|
||||
* Buscar pedidos com cache baseado nos filtros
|
||||
* @param query - Filtros para busca de pedidos
|
||||
* @returns Lista de pedidos
|
||||
*/
|
||||
async findOrders(query: FindOrdersDto) {
|
||||
async findOrders(query: FindOrdersDto): Promise<OrderResponseDto[]> {
|
||||
const key = `orders:query:${this.hashObject(query)}`;
|
||||
|
||||
return getOrSetCache(
|
||||
@@ -52,21 +57,23 @@ export class OrdersService {
|
||||
async () => {
|
||||
const orders = await this.ordersRepository.findOrders(query);
|
||||
|
||||
if (query.includeCompletedDeliveries) {
|
||||
for (const order of orders) {
|
||||
const deliveryQuery = {
|
||||
orderNumber: order.invoiceNumber,
|
||||
limit: 10,
|
||||
offset: 0
|
||||
};
|
||||
|
||||
try {
|
||||
const deliveries = await this.ordersRepository.getCompletedDeliveries(deliveryQuery);
|
||||
order.completedDeliveries = deliveries;
|
||||
} catch (error) {
|
||||
// Se houver erro, definir como array vazio
|
||||
order.completedDeliveries = [];
|
||||
}
|
||||
if (!query.includeCompletedDeliveries) {
|
||||
return orders;
|
||||
}
|
||||
|
||||
for (const order of orders) {
|
||||
const deliveryQuery = {
|
||||
orderNumber: order.invoiceNumber,
|
||||
limit: 10,
|
||||
offset: 0
|
||||
};
|
||||
|
||||
try {
|
||||
const deliveries = await this.ordersRepository.getCompletedDeliveries(deliveryQuery);
|
||||
order.completedDeliveries = deliveries;
|
||||
} catch (error) {
|
||||
// Se houver erro, definir como array vazio
|
||||
order.completedDeliveries = [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,8 +84,10 @@ export class OrdersService {
|
||||
|
||||
/**
|
||||
* Buscar pedidos por data de entrega com cache
|
||||
* @param query - Filtros para busca por data de entrega
|
||||
* @returns Lista de pedidos
|
||||
*/
|
||||
async findOrdersByDeliveryDate(query: any) {
|
||||
async findOrdersByDeliveryDate(query: FindOrdersByDeliveryDateDto): Promise<OrderResponseDto[]> {
|
||||
const key = `orders:delivery:${this.hashObject(query)}`;
|
||||
return getOrSetCache(
|
||||
this.redisClient,
|
||||
@@ -90,8 +99,10 @@ export class OrdersService {
|
||||
|
||||
/**
|
||||
* Buscar pedidos com resultados de fechamento de caixa
|
||||
* @param query - Filtros para busca de pedidos
|
||||
* @returns Lista de pedidos com dados de fechamento de caixa
|
||||
*/
|
||||
async findOrdersWithCheckout(query: FindOrdersDto) {
|
||||
async findOrdersWithCheckout(query: FindOrdersDto): Promise<(OrderResponseDto & { checkout: any })[]> {
|
||||
const key = `orders:checkout:${this.hashObject(query)}`;
|
||||
return getOrSetCache(
|
||||
this.redisClient,
|
||||
@@ -236,28 +247,30 @@ export class OrdersService {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (includeCompletedDeliveries) {
|
||||
try {
|
||||
// Buscar entregas realizadas usando o transactionId do pedido
|
||||
// Primeiro precisamos obter o NUMTRANSVENDA do pedido
|
||||
const transactionId = await this.ordersRepository.getOrderTransactionId(orderId);
|
||||
|
||||
if (transactionId) {
|
||||
const deliveryQuery = {
|
||||
transactionId: transactionId,
|
||||
limit: 10,
|
||||
offset: 0
|
||||
};
|
||||
|
||||
const deliveries = await this.ordersRepository.getCompletedDeliveriesByTransactionId(deliveryQuery);
|
||||
orderDelivery.completedDeliveries = deliveries;
|
||||
} else {
|
||||
orderDelivery.completedDeliveries = [];
|
||||
}
|
||||
} catch (error) {
|
||||
// Se houver erro, definir como array vazio
|
||||
if (!includeCompletedDeliveries) {
|
||||
return orderDelivery;
|
||||
}
|
||||
|
||||
try {
|
||||
// Buscar entregas realizadas usando o transactionId do pedido
|
||||
const transactionId = await this.ordersRepository.getOrderTransactionId(orderId);
|
||||
|
||||
if (!transactionId) {
|
||||
orderDelivery.completedDeliveries = [];
|
||||
return orderDelivery;
|
||||
}
|
||||
|
||||
const deliveryQuery = {
|
||||
transactionId: transactionId,
|
||||
limit: 10,
|
||||
offset: 0
|
||||
};
|
||||
|
||||
const deliveries = await this.ordersRepository.getCompletedDeliveriesByTransactionId(deliveryQuery);
|
||||
orderDelivery.completedDeliveries = deliveries;
|
||||
} catch (error) {
|
||||
// Se houver erro, definir como array vazio
|
||||
orderDelivery.completedDeliveries = [];
|
||||
}
|
||||
|
||||
return orderDelivery;
|
||||
@@ -322,10 +335,14 @@ export class OrdersService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Utilitário para gerar hash MD5 de objetos
|
||||
* Utilitário para gerar hash MD5 de objetos para chaves de cache
|
||||
* @param obj - Objeto a ser serializado e hasheado
|
||||
* @returns Hash MD5 do objeto serializado
|
||||
*/
|
||||
private hashObject(obj: any): string {
|
||||
const str = JSON.stringify(obj, Object.keys(obj).sort());
|
||||
private hashObject(obj: unknown): string {
|
||||
const objRecord = obj as Record<string, unknown>;
|
||||
const sortedKeys = Object.keys(objRecord).sort();
|
||||
const str = JSON.stringify(objRecord, sortedKeys);
|
||||
return createHash('md5').update(str).digest('hex');
|
||||
}
|
||||
|
||||
|
||||
@@ -1,49 +1,46 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Query,
|
||||
UsePipes,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
ValidationPipe,
|
||||
} from '@nestjs/common';
|
||||
import { ApiOperation, ApiTags, ApiResponse } from '@nestjs/swagger';
|
||||
import { DebService } from '../application/deb.service';
|
||||
import { DebDto } from '../dto/DebDto';
|
||||
import { FindDebDto } from '../dto/find-deb.dto';
|
||||
|
||||
@ApiTags('Débitos')
|
||||
@Controller('api/v1/deb')
|
||||
export class DebController {
|
||||
constructor(private readonly debService: DebService) {}
|
||||
|
||||
@Get('find-by-cpf')
|
||||
@ApiOperation({
|
||||
summary: 'Busca débitos por CPF/CGCENT',
|
||||
description: 'Busca débitos de um cliente usando CPF ou CGCENT. Opcionalmente pode filtrar por matrícula do funcionário ou código de cobrança.',
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Lista de débitos retornada com sucesso',
|
||||
type: [DebDto],
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'CPF/CGCENT é obrigatório',
|
||||
})
|
||||
@UsePipes(new ValidationPipe({ transform: true }))
|
||||
async findByCpfCgcent(
|
||||
@Query() query: FindDebDto,
|
||||
): Promise<DebDto[]> {
|
||||
try {
|
||||
return await this.debService.findByCpfCgcent(query.cpfCgcent, query.matricula, query.cobranca);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Erro ao buscar débitos',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
Controller,
|
||||
Get,
|
||||
Query,
|
||||
UsePipes,
|
||||
ValidationPipe,
|
||||
} from '@nestjs/common';
|
||||
import { ApiOperation, ApiTags, ApiResponse } from '@nestjs/swagger';
|
||||
import { DebService } from '../application/deb.service';
|
||||
import { DebDto } from '../dto/DebDto';
|
||||
import { FindDebDto } from '../dto/find-deb.dto';
|
||||
|
||||
@ApiTags('Débitos')
|
||||
@Controller('api/v1/deb')
|
||||
export class DebController {
|
||||
constructor(private readonly debService: DebService) {}
|
||||
|
||||
@Get('find-by-cpf')
|
||||
@ApiOperation({
|
||||
summary: 'Busca débitos por CPF/CGCENT',
|
||||
description: 'Busca débitos de um cliente usando CPF ou CGCENT. Opcionalmente pode filtrar por matrícula do funcionário ou código de cobrança.',
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Lista de débitos retornada com sucesso',
|
||||
type: [DebDto],
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 400,
|
||||
description: 'CPF/CGCENT é obrigatório',
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 500,
|
||||
description: 'Erro interno do servidor',
|
||||
})
|
||||
@UsePipes(new ValidationPipe({ transform: true }))
|
||||
async findByCpfCgcent(
|
||||
@Query() query: FindDebDto,
|
||||
): Promise<DebDto[]> {
|
||||
return await this.debService.findByCpfCgcent(
|
||||
query.cpfCgcent,
|
||||
query.matricula,
|
||||
query.cobranca,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import {
|
||||
HttpStatus,
|
||||
DefaultValuePipe,
|
||||
ParseBoolPipe,
|
||||
Optional,
|
||||
} from '@nestjs/common';
|
||||
import { ApiBearerAuth, ApiOperation, ApiTags, ApiQuery, ApiParam, ApiResponse } from '@nestjs/swagger';
|
||||
import { ResponseInterceptor } from '../../common/response.interceptor';
|
||||
@@ -34,8 +33,6 @@ import { CarrierDto } from 'src/data-consult/dto/carrier.dto';
|
||||
import { OrderResponseDto } from '../dto/order-response.dto';
|
||||
import { MarkResponseDto } from '../dto/mark-response.dto';
|
||||
import { EstLogTransferResponseDto } from '../dto/estlogtransfer.dto';
|
||||
import { DeliveryCompletedQuery } from '../dto/delivery-completed-query.dto';
|
||||
import { DeliveryCompleted } from '../dto/delivery-completed.dto';
|
||||
|
||||
|
||||
@ApiTags('Orders')
|
||||
@@ -51,9 +48,6 @@ export class OrdersController {
|
||||
description: 'Busca pedidos com filtros avançados. Suporta filtros por data, cliente, vendedor, status, tipo de entrega e status de transferência.'
|
||||
})
|
||||
@ApiQuery({ name: 'includeCheckout', required: false, type: 'boolean', description: 'Incluir dados de checkout' })
|
||||
@ApiQuery({ name: 'includeCompletedDeliveries', required: false, type: 'boolean', description: 'Incluir dados de entregas realizadas para cada pedido' })
|
||||
@ApiQuery({ name: 'limit', required: false, type: 'number', description: 'Limite de registros por página', example: 100 })
|
||||
@ApiQuery({ name: 'offset', required: false, type: 'number', description: 'Offset para paginação', example: 0 })
|
||||
@ApiQuery({ name: 'statusTransfer', required: false, type: 'string', description: 'Filtrar por status de transferência (Em Trânsito, Em Separação, Aguardando Separação, Concluída)' })
|
||||
@ApiQuery({ name: 'markId', required: false, type: 'number', description: 'ID da marca para filtrar pedidos' })
|
||||
@ApiQuery({ name: 'markName', required: false, type: 'string', description: 'Nome da marca para filtrar pedidos (busca parcial)' })
|
||||
@@ -90,7 +84,7 @@ export class OrdersController {
|
||||
|
||||
@Get(':orderId/checkout')
|
||||
@ApiOperation({ summary: 'Busca fechamento de caixa para um pedido' })
|
||||
@ApiParam({ name: 'orderId', example: 236001388 })
|
||||
@ApiParam({ name: 'orderId' })
|
||||
@UsePipes(new ValidationPipe({ transform: true }))
|
||||
getOrderCheckout(
|
||||
@Param('orderId', ParseIntPipe) orderId: number,
|
||||
@@ -104,7 +98,6 @@ export class OrdersController {
|
||||
name: 'chavenfe',
|
||||
required: true,
|
||||
description: 'Chave da Nota Fiscal (44 dígitos)',
|
||||
example: '35191234567890000123550010000000011000000010',
|
||||
})
|
||||
|
||||
@ApiOperation({ summary: 'Busca NF pela chave' })
|
||||
@@ -122,7 +115,7 @@ export class OrdersController {
|
||||
|
||||
@Get('itens/:orderId')
|
||||
@ApiOperation({ summary: 'Busca PELO numero do pedido' })
|
||||
@ApiParam({ name: 'orderId', example: '236001388' })
|
||||
@ApiParam({ name: 'orderId' })
|
||||
@UsePipes(new ValidationPipe({ transform: true }))
|
||||
async getItens(@Param('orderId', ParseIntPipe) orderId: number): Promise<OrderItemDto[]> {
|
||||
try {
|
||||
@@ -136,7 +129,7 @@ export class OrdersController {
|
||||
}
|
||||
@Get('cut-itens/:orderId')
|
||||
@ApiOperation({ summary: 'Busca itens cortados do pedido' })
|
||||
@ApiParam({ name: 'orderId', example: '236001388' })
|
||||
@ApiParam({ name: 'orderId' })
|
||||
@UsePipes(new ValidationPipe({ transform: true }))
|
||||
async getCutItens(@Param('orderId', ParseIntPipe) orderId: number): Promise<CutItemDto[]> {
|
||||
try {
|
||||
@@ -151,16 +144,11 @@ export class OrdersController {
|
||||
|
||||
@Get('delivery/:orderId')
|
||||
@ApiOperation({ summary: 'Busca dados de entrega do pedido' })
|
||||
@ApiParam({ name: 'orderId', example: '236001388' })
|
||||
@ApiQuery({ name: 'includeCompletedDeliveries', required: false, type: 'boolean', description: 'Incluir dados de entregas realizadas para o pedido' })
|
||||
@ApiParam({ name: 'orderId' })
|
||||
@UsePipes(new ValidationPipe({ transform: true }))
|
||||
async getOrderDelivery(
|
||||
@Param('orderId', ParseIntPipe) orderId: number,
|
||||
@Query('includeCompletedDeliveries', new DefaultValuePipe(false), ParseBoolPipe)
|
||||
includeCompletedDeliveries: boolean,
|
||||
): Promise<OrderDeliveryDto | null> {
|
||||
async getOrderDelivery(@Param('orderId', ParseIntPipe) orderId: number): Promise<OrderDeliveryDto | null> {
|
||||
try {
|
||||
return await this.ordersService.getOrderDelivery(orderId.toString(), includeCompletedDeliveries);
|
||||
return await this.ordersService.getOrderDelivery(orderId.toString());
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Erro ao buscar dados de entrega',
|
||||
@@ -171,7 +159,7 @@ export class OrdersController {
|
||||
|
||||
@Get('transfer/:orderId')
|
||||
@ApiOperation({ summary: 'Consulta pedidos de transferência' })
|
||||
@ApiParam({ name: 'orderId', example: 236001388 })
|
||||
@ApiParam({ name: 'orderId' })
|
||||
@UsePipes(new ValidationPipe({ transform: true }))
|
||||
async getTransfer(@Param('orderId', ParseIntPipe) orderId: number): Promise<OrderTransferDto[] | null> {
|
||||
try {
|
||||
@@ -186,7 +174,7 @@ export class OrdersController {
|
||||
|
||||
@Get('status/:orderId')
|
||||
@ApiOperation({ summary: 'Consulta status do pedido' })
|
||||
@ApiParam({ name: 'orderId', example: 236001388 })
|
||||
@ApiParam({ name: 'orderId' })
|
||||
@UsePipes(new ValidationPipe({ transform: true }))
|
||||
async getStatusOrder(@Param('orderId', ParseIntPipe) orderId: number): Promise<OrderStatusDto[] | null> {
|
||||
try {
|
||||
@@ -202,7 +190,7 @@ export class OrdersController {
|
||||
|
||||
@Get(':orderId/deliveries')
|
||||
@ApiOperation({ summary: 'Consulta entregas do pedido' })
|
||||
@ApiParam({ name: 'orderId', example: '236001388' })
|
||||
@ApiParam({ name: 'orderId' })
|
||||
@ApiQuery({ name: 'createDateIni', required: false, description: 'Data inicial para filtro (formato YYYY-MM-DD)' })
|
||||
@ApiQuery({ name: 'createDateEnd', required: false, description: 'Data final para filtro (formato YYYY-MM-DD)' })
|
||||
async getOrderDeliveries(
|
||||
@@ -223,7 +211,7 @@ export class OrdersController {
|
||||
|
||||
@Get('leadtime/:orderId')
|
||||
@ApiOperation({ summary: 'Consulta leadtime do pedido' })
|
||||
@ApiParam({ name: 'orderId', example: '236001388' })
|
||||
@ApiParam({ name: 'orderId' })
|
||||
@UsePipes(new ValidationPipe({ transform: true }))
|
||||
async getLeadtime(@Param('orderId', ParseIntPipe) orderId: number): Promise<LeadtimeDto[]> {
|
||||
try {
|
||||
@@ -315,7 +303,7 @@ async getMarksByName(@Query('name') markName: string): Promise<MarkResponseDto[]
|
||||
|
||||
@Get('transfer-log/:orderId')
|
||||
@ApiOperation({ summary: 'Busca log de transferência por ID do pedido' })
|
||||
@ApiParam({ name: 'orderId', example: 153068638, description: 'ID do pedido para buscar log de transferência' })
|
||||
@ApiParam({ name: 'orderId', description: 'ID do pedido para buscar log de transferência' })
|
||||
@ApiQuery({ name: 'dttransf', required: false, type: 'string', description: 'Data de transferência (formato YYYY-MM-DD)' })
|
||||
@ApiQuery({ name: 'codfilial', required: false, type: 'number', description: 'Código da filial de origem' })
|
||||
@ApiQuery({ name: 'codfilialdest', required: false, type: 'number', description: 'Código da filial de destino' })
|
||||
@@ -391,62 +379,4 @@ async getTransferLogs(
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Get('completed-deliveries')
|
||||
@ApiOperation({
|
||||
summary: 'Busca entregas realizadas',
|
||||
description: 'Busca entregas realizadas com filtros opcionais por data, cliente, motorista, status e outros critérios.'
|
||||
})
|
||||
@ApiQuery({ name: 'startDate', required: false, type: 'string', description: 'Data de início (formato YYYY-MM-DD)' })
|
||||
@ApiQuery({ name: 'endDate', required: false, type: 'string', description: 'Data de fim (formato YYYY-MM-DD)' })
|
||||
@ApiQuery({ name: 'outId', required: false, type: 'number', description: 'ID da saída' })
|
||||
@ApiQuery({ name: 'driverName', required: false, type: 'string', description: 'Nome do motorista' })
|
||||
@ApiQuery({ name: 'customerId', required: false, type: 'number', description: 'ID do cliente' })
|
||||
@ApiQuery({ name: 'customerName', required: false, type: 'string', description: 'Nome do cliente' })
|
||||
@ApiQuery({ name: 'orderNumber', required: false, type: 'string', description: 'Número da nota fiscal' })
|
||||
@ApiQuery({ name: 'status', required: false, type: 'string', description: 'Status da entrega' })
|
||||
@ApiQuery({ name: 'limit', required: false, type: 'number', description: 'Limite de registros por página', example: 100 })
|
||||
@ApiQuery({ name: 'offset', required: false, type: 'number', description: 'Offset para paginação', example: 0 })
|
||||
@UsePipes(new ValidationPipe({ transform: true }))
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Entregas realizadas encontradas com sucesso',
|
||||
type: [DeliveryCompleted]
|
||||
})
|
||||
@ApiResponse({ status: 400, description: 'Parâmetros inválidos' })
|
||||
@ApiResponse({ status: 500, description: 'Erro interno do servidor' })
|
||||
async getCompletedDeliveries(
|
||||
@Query('startDate') startDate?: string,
|
||||
@Query('endDate') endDate?: string,
|
||||
@Query('outId') outId?: string,
|
||||
@Query('driverName') driverName?: string,
|
||||
@Query('customerId') customerId?: string,
|
||||
@Query('customerName') customerName?: string,
|
||||
@Query('orderNumber') orderNumber?: string,
|
||||
@Query('status') status?: string,
|
||||
@Query('limit', new DefaultValuePipe(100), ParseIntPipe) limit: number = 100,
|
||||
@Query('offset', new DefaultValuePipe(0), ParseIntPipe) offset: number = 0,
|
||||
) {
|
||||
try {
|
||||
const query: DeliveryCompletedQuery = {
|
||||
startDate,
|
||||
endDate,
|
||||
outId: outId ? parseInt(outId, 10) : undefined,
|
||||
driverName,
|
||||
customerId: customerId ? parseInt(customerId, 10) : undefined,
|
||||
customerName,
|
||||
orderNumber,
|
||||
status,
|
||||
limit,
|
||||
offset,
|
||||
};
|
||||
|
||||
return await this.ordersService.getCompletedDeliveries(query);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'Erro ao buscar entregas realizadas',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
78
src/orders/dto/DebDto.ts
Normal file
78
src/orders/dto/DebDto.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class DebDto {
|
||||
@ApiProperty({
|
||||
description: 'Data de emissão',
|
||||
example: '2024-01-15T00:00:00Z',
|
||||
})
|
||||
dtemissao: Date;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Código da filial',
|
||||
example: '001',
|
||||
})
|
||||
codfilial: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Número da duplicata',
|
||||
example: '123456',
|
||||
})
|
||||
duplic: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Número da prestação',
|
||||
example: '1',
|
||||
})
|
||||
prest: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Código do cliente',
|
||||
example: 12345,
|
||||
})
|
||||
codcli: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Nome do cliente',
|
||||
example: 'João da Silva',
|
||||
})
|
||||
cliente: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Código de cobrança',
|
||||
example: 'BOL',
|
||||
})
|
||||
codcob: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Descrição da cobrança',
|
||||
example: 'Boleto',
|
||||
})
|
||||
cobranca: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Data de vencimento',
|
||||
example: '2024-02-15T00:00:00Z',
|
||||
})
|
||||
dtvenc: Date;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Data de pagamento',
|
||||
example: '2024-02-10T00:00:00Z',
|
||||
required: false,
|
||||
})
|
||||
dtpag: Date | null;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Valor do débito',
|
||||
example: 1500.00,
|
||||
})
|
||||
valor: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Situação do débito',
|
||||
example: 'A VENCER',
|
||||
enum: ['PAGO', 'EM ATRASO', 'A VENCER', 'NENHUM'],
|
||||
})
|
||||
situacao: string;
|
||||
}
|
||||
|
||||
@@ -38,12 +38,12 @@ export class FindOrdersByDeliveryDateDto {
|
||||
codfilial?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@IsString()
|
||||
@ApiPropertyOptional({
|
||||
description: 'ID do vendedor',
|
||||
example: 123
|
||||
description: 'ID do vendedor (separado por vírgula para múltiplos valores)',
|
||||
example: '270,431'
|
||||
})
|
||||
sellerId?: number;
|
||||
sellerId?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
|
||||
@@ -66,10 +66,10 @@ export class FindOrdersDto {
|
||||
stockId?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@IsString()
|
||||
@ApiPropertyOptional()
|
||||
|
||||
sellerId?: number;
|
||||
sellerId?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@@ -158,7 +158,6 @@ sellerName?: string;
|
||||
@IsString()
|
||||
@ApiPropertyOptional({
|
||||
description: 'Filtrar por status de transferência',
|
||||
example: 'Em Trânsito,Em Separação,Aguardando Separação,Concluída',
|
||||
enum: ['Em Trânsito', 'Em Separação', 'Aguardando Separação', 'Concluída']
|
||||
})
|
||||
statusTransfer?: string;
|
||||
@@ -182,40 +181,35 @@ sellerName?: string;
|
||||
@Type(() => Boolean)
|
||||
@IsBoolean()
|
||||
@ApiPropertyOptional({
|
||||
description: 'Filtrar pedidos que tenham registros na tabela de transfer log',
|
||||
example: true
|
||||
description: 'Filtrar pedidos que tenham registros na tabela de transfer log'
|
||||
})
|
||||
hasPreBox?: boolean;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@ApiPropertyOptional({
|
||||
description: 'Código da filial de origem da transferência (Pre-Box)',
|
||||
example: '5'
|
||||
description: 'Código da filial de origem da transferência (Pre-Box)'
|
||||
})
|
||||
preBoxFilial?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@ApiPropertyOptional({
|
||||
description: 'Código da filial de destino da transferência',
|
||||
example: '6'
|
||||
description: 'Código da filial de destino da transferência'
|
||||
})
|
||||
transferDestFilial?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
@ApiPropertyOptional({
|
||||
description: 'Data de transferência inicial (formato YYYY-MM-DD)',
|
||||
example: '2024-01-01'
|
||||
description: 'Data de transferência inicial (formato YYYY-MM-DD)'
|
||||
})
|
||||
transferDateIni?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
@ApiPropertyOptional({
|
||||
description: 'Data de transferência final (formato YYYY-MM-DD)',
|
||||
example: '2024-12-31'
|
||||
description: 'Data de transferência final (formato YYYY-MM-DD)'
|
||||
})
|
||||
transferDateEnd?: string;
|
||||
|
||||
@@ -223,8 +217,7 @@ sellerName?: string;
|
||||
@Type(() => Boolean)
|
||||
@IsBoolean()
|
||||
@ApiPropertyOptional({
|
||||
description: 'Incluir dados de entregas realizadas para cada pedido',
|
||||
example: false
|
||||
description: 'Incluir dados de entregas realizadas para cada pedido'
|
||||
})
|
||||
includeCompletedDeliveries?: boolean;
|
||||
|
||||
@@ -232,8 +225,7 @@ sellerName?: string;
|
||||
@Type(() => Number)
|
||||
@IsNumber()
|
||||
@ApiPropertyOptional({
|
||||
description: 'Limite de registros por página',
|
||||
example: 100
|
||||
description: 'Limite de registros por página'
|
||||
})
|
||||
limit?: number;
|
||||
|
||||
@@ -241,8 +233,7 @@ sellerName?: string;
|
||||
@Type(() => Number)
|
||||
@IsNumber()
|
||||
@ApiPropertyOptional({
|
||||
description: 'Offset para paginação',
|
||||
example: 0
|
||||
description: 'Offset para paginação'
|
||||
})
|
||||
offset?: number;
|
||||
}
|
||||
|
||||
@@ -3,308 +3,258 @@ import { ApiProperty } from '@nestjs/swagger';
|
||||
export class OrderResponseDto {
|
||||
@ApiProperty({
|
||||
description: 'Data de criação do pedido',
|
||||
example: '2024-04-02T10:00:00Z',
|
||||
})
|
||||
createDate: Date;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'ID da loja',
|
||||
example: '001 - Pre-Box (002)',
|
||||
})
|
||||
storeId: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'ID do pedido',
|
||||
example: 12345,
|
||||
})
|
||||
orderId: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'ID do cliente',
|
||||
example: '12345',
|
||||
})
|
||||
customerId: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Nome do cliente',
|
||||
example: '12345 - João da Silva',
|
||||
})
|
||||
customerName: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'ID do vendedor',
|
||||
example: '001',
|
||||
})
|
||||
sellerId: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Nome do vendedor',
|
||||
example: '001 - Maria Santos',
|
||||
})
|
||||
sellerName: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Nome da loja',
|
||||
example: 'Loja Centro',
|
||||
})
|
||||
store: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Tipo de entrega',
|
||||
example: 'Entrega (EN)',
|
||||
})
|
||||
deliveryType: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Local de entrega',
|
||||
example: '001-Centro',
|
||||
})
|
||||
deliveryLocal: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Local de entrega principal',
|
||||
example: '001-Rota Centro',
|
||||
})
|
||||
masterDeliveryLocal: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Tipo do pedido',
|
||||
example: 'TV8 - Entrega (EN)',
|
||||
})
|
||||
orderType: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Valor total do pedido',
|
||||
example: 1000.00,
|
||||
})
|
||||
amount: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Data de entrega',
|
||||
example: '2024-04-05T10:00:00Z',
|
||||
})
|
||||
deliveryDate: Date;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Prioridade de entrega',
|
||||
example: 'Alta',
|
||||
})
|
||||
deliveryPriority: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'ID do carregamento',
|
||||
example: 123,
|
||||
})
|
||||
shipmentId: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Data de liberação',
|
||||
example: '2024-04-02T10:00:00Z',
|
||||
})
|
||||
releaseDate: Date;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Usuário de liberação',
|
||||
example: '001',
|
||||
})
|
||||
releaseUser: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Nome do usuário de liberação',
|
||||
example: '001 - João Silva',
|
||||
})
|
||||
releaseUserName: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Data de saída do carregamento',
|
||||
example: '2024-04-03T10:00:00Z',
|
||||
})
|
||||
shipmentDate: Date;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Data de criação do carregamento',
|
||||
example: '2024-04-02T10:00:00Z',
|
||||
})
|
||||
shipmentDateCreate: Date;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Data de fechamento do carregamento',
|
||||
example: '2024-04-03T18:00:00Z',
|
||||
})
|
||||
shipmentCloseDate: Date;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'ID do plano de pagamento',
|
||||
example: '001',
|
||||
})
|
||||
paymentId: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Nome do plano de pagamento',
|
||||
example: 'Cartão de Crédito',
|
||||
})
|
||||
paymentName: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'ID da cobrança',
|
||||
example: '001',
|
||||
})
|
||||
billingId: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Nome da cobrança',
|
||||
example: '001 - Cartão de Crédito',
|
||||
})
|
||||
billingName: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Data de faturamento',
|
||||
example: '2024-04-02T10:00:00Z',
|
||||
})
|
||||
invoiceDate: Date;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Hora de faturamento',
|
||||
example: 10,
|
||||
})
|
||||
invoiceHour: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Minuto de faturamento',
|
||||
example: 30,
|
||||
})
|
||||
invoiceMinute: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Número da nota fiscal',
|
||||
example: 123456,
|
||||
})
|
||||
invoiceNumber: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Descrição do bloqueio',
|
||||
example: 'Cliente com restrição',
|
||||
})
|
||||
BloqDescription: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Data de confirmação de entrega',
|
||||
example: '2024-04-05T15:00:00Z',
|
||||
})
|
||||
confirmDeliveryDate: Date;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Peso total',
|
||||
example: 50.5,
|
||||
})
|
||||
totalWeigth: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Processo do pedido',
|
||||
example: 3,
|
||||
})
|
||||
processOrder: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Status do pedido',
|
||||
example: 'FATURADO',
|
||||
})
|
||||
status: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Pagamento',
|
||||
example: 0,
|
||||
})
|
||||
payment: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Motorista',
|
||||
example: '001 - João Silva',
|
||||
})
|
||||
driver: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'ID do pedido de venda',
|
||||
example: 12346,
|
||||
})
|
||||
orderSaleId: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Descrição do carro',
|
||||
example: 'Fiat Fiorino (ABC1234)',
|
||||
})
|
||||
carDescription: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Identificação do carro',
|
||||
example: 'ABC1234',
|
||||
})
|
||||
carIdentification: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Transportadora',
|
||||
example: '001 - Transportadora XYZ',
|
||||
})
|
||||
carrier: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Status da transferência',
|
||||
example: 'Em Trânsito',
|
||||
nullable: true,
|
||||
})
|
||||
statusTransfer: string | null;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Loja Pre-Box',
|
||||
example: '002',
|
||||
})
|
||||
storePreBox: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Código do emitente da nota fiscal',
|
||||
example: 32,
|
||||
nullable: true,
|
||||
})
|
||||
codEmitente: number | null;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Matrícula do funcionário emitente',
|
||||
example: 32,
|
||||
nullable: true,
|
||||
})
|
||||
emitenteMatricula: number | null;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Nome do funcionário emitente',
|
||||
example: 'João Silva',
|
||||
nullable: true,
|
||||
})
|
||||
emitenteNome: string | null;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Código do funcionário de faturamento',
|
||||
example: 1336,
|
||||
nullable: true,
|
||||
})
|
||||
fatUserCode: number | null;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Nome do funcionário de faturamento',
|
||||
example: 'ADRIANO COSTA DA SILVA',
|
||||
nullable: true,
|
||||
})
|
||||
fatUserName: string | null;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Descrição completa do funcionário de faturamento',
|
||||
example: '1336-ADRIANO COSTA DA SILVA',
|
||||
nullable: true,
|
||||
})
|
||||
fatUserDescription: string | null;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Entrega agendada',
|
||||
example: 'ENTREGA NORMAL',
|
||||
})
|
||||
schedulerDelivery: string;
|
||||
}
|
||||
}
|
||||
|
||||
6
src/orders/interface/deb.interface.ts
Normal file
6
src/orders/interface/deb.interface.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export interface DebQueryParams {
|
||||
cpfCgcent: string;
|
||||
matricula?: number;
|
||||
}
|
||||
|
||||
|
||||
18
src/orders/modules/deb.module.ts
Normal file
18
src/orders/modules/deb.module.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { DebController } from '../controllers/deb.controller';
|
||||
import { DebService } from '../application/deb.service';
|
||||
import { DebRepository } from '../repositories/deb.repository';
|
||||
import { DatabaseModule } from '../../core/database/database.module';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule,
|
||||
DatabaseModule,
|
||||
],
|
||||
controllers: [DebController],
|
||||
providers: [DebService, DebRepository],
|
||||
exports: [DebService],
|
||||
})
|
||||
export class DebModule {}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { DataSource } from 'typeorm';
|
||||
import { InjectDataSource } from '@nestjs/typeorm';
|
||||
import { DebDto } from '../dto/DebDto';
|
||||
|
||||
@Injectable()
|
||||
export class DebRepository {
|
||||
@@ -15,8 +15,9 @@ export class DebRepository {
|
||||
* @param matricula - Matrícula do funcionário (opcional)
|
||||
* @param cobranca - Código de cobrança (opcional)
|
||||
* @returns Lista de débitos do cliente
|
||||
* @throws {Error} Erro ao executar a query no banco de dados
|
||||
*/
|
||||
async findByCpfCgcent(cpfCgcent: string, matricula?: number, cobranca?: string) {
|
||||
async findByCpfCgcent(cpfCgcent: string, matricula?: number, cobranca?: string): Promise<DebDto[]> {
|
||||
const queryRunner = this.oracleDataSource.createQueryRunner();
|
||||
await queryRunner.connect();
|
||||
try {
|
||||
|
||||
@@ -403,7 +403,12 @@ WHERE
|
||||
);
|
||||
}
|
||||
if (query.sellerId) {
|
||||
conditions.push(`AND PCPEDC.CODUSUR = :sellerId`);
|
||||
const sellerIds = query.sellerId
|
||||
.split(",")
|
||||
.map((s) => s.trim())
|
||||
.filter((s) => s)
|
||||
.join(",");
|
||||
conditions.push(`AND PCPEDC.CODUSUR IN (${sellerIds})`);
|
||||
}
|
||||
if (query.customerId) {
|
||||
conditions.push(`AND PCPEDC.CODCLI = :customerId`);
|
||||
@@ -572,9 +577,6 @@ WHERE
|
||||
if (query.filialretira) {
|
||||
parameters.storeStockId = query.filialretira;
|
||||
}
|
||||
if (query.sellerId) {
|
||||
parameters.sellerId = query.sellerId;
|
||||
}
|
||||
if (query.customerId) {
|
||||
parameters.customerId = query.customerId;
|
||||
}
|
||||
@@ -805,7 +807,12 @@ WHERE
|
||||
conditions.push(`AND PCPEDC.CODFILIAL = :storeId`);
|
||||
}
|
||||
if (query.sellerId) {
|
||||
conditions.push(`AND PCPEDC.CODUSUR = :sellerId`);
|
||||
const sellerIds = query.sellerId
|
||||
.split(",")
|
||||
.map((s) => s.trim())
|
||||
.filter((s) => s)
|
||||
.join(",");
|
||||
conditions.push(`AND PCPEDC.CODUSUR IN (${sellerIds})`);
|
||||
}
|
||||
if (query.customerId) {
|
||||
conditions.push(`AND PCPEDC.CODCLI = :customerId`);
|
||||
@@ -889,9 +896,6 @@ WHERE
|
||||
if (query.codfilial) {
|
||||
parameters.storeId = query.codfilial;
|
||||
}
|
||||
if (query.sellerId) {
|
||||
parameters.sellerId = query.sellerId;
|
||||
}
|
||||
if (query.customerId) {
|
||||
parameters.customerId = query.customerId;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user