feat: adiciona filtro de cobrança e converte para query builder no deb.repository

This commit is contained in:
JurTI-BR
2025-11-02 15:15:17 -03:00
parent 893a7c5b0a
commit 3849fa1c4e
4 changed files with 184 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { DebRepository } from '../repositories/deb.repository';
import { DebDto } from '../dto/DebDto';
@Injectable()
export class DebService {
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,
);
}
}
}

View File

@@ -0,0 +1,49 @@
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,
);
}
}
}

View File

@@ -0,0 +1,34 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsString, IsNumber, IsNotEmpty, IsOptional, MinLength } from 'class-validator';
import { Type } from 'class-transformer';
export class FindDebDto {
@IsNotEmpty({ message: 'CPF/CGCENT é obrigatório' })
@IsString({ message: 'CPF/CGCENT deve ser uma string' })
@MinLength(11, { message: 'CPF/CGCENT deve ter no mínimo 11 caracteres' })
@ApiProperty({
description: 'CPF ou CGCENT do cliente',
example: '70290642167',
minLength: 11,
})
cpfCgcent: string;
@IsOptional()
@IsNumber({}, { message: 'Matrícula deve ser um número' })
@Type(() => Number)
@ApiPropertyOptional({
description: 'Matrícula do funcionário (opcional)',
example: 1498,
type: Number,
})
matricula?: number;
@IsOptional()
@IsString({ message: 'Cobrança deve ser uma string' })
@ApiPropertyOptional({
description: 'Código de cobrança (opcional)',
example: 'BOL',
})
cobranca?: string;
}

View File

@@ -0,0 +1,67 @@
import { Injectable } from '@nestjs/common';
import { DataSource } from 'typeorm';
import { InjectDataSource } from '@nestjs/typeorm';
@Injectable()
export class DebRepository {
constructor(
@InjectDataSource("oracle") private readonly oracleDataSource: DataSource,
) {}
/**
* Busca débitos por CPF/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) {
const queryRunner = this.oracleDataSource.createQueryRunner();
await queryRunner.connect();
try {
const queryBuilder = queryRunner.manager
.createQueryBuilder()
.select([
'p.dtemissao AS "dtemissao"',
'p.codfilial AS "codfilial"',
'p.duplic AS "duplic"',
'p.prest AS "prest"',
'p.codcli AS "codcli"',
'c.cliente AS "cliente"',
'p.codcob AS "codcob"',
'cb.cobranca AS "cobranca"',
'p.dtvenc AS "dtvenc"',
'p.dtpag AS "dtpag"',
'p.valor AS "valor"',
`CASE
WHEN p.dtpag IS NOT NULL THEN 'PAGO'
WHEN p.dtvenc < TRUNC(SYSDATE) THEN 'EM ATRASO'
WHEN p.dtvenc >= TRUNC(SYSDATE) THEN 'A VENCER'
ELSE 'NENHUM'
END AS "situacao"`,
])
.from('pcprest', 'p')
.innerJoin('pcclient', 'c', 'p.codcli = c.codcli')
.innerJoin('pccob', 'cb', 'p.codcob = cb.codcob')
.innerJoin('pcempr', 'e', 'c.cgcent = e.cpf')
.where('p.codcob NOT IN (:...excludedCob)', { excludedCob: ['DESD', 'CANC'] })
.andWhere('c.cgcent = :cpfCgcent', { cpfCgcent });
if (matricula) {
queryBuilder.andWhere('e.matricula = :matricula', { matricula });
}
if (cobranca) {
queryBuilder.andWhere('p.codcob = :cobranca', { cobranca });
}
queryBuilder.orderBy('p.dtvenc', 'ASC');
const result = await queryBuilder.getRawMany();
return result;
} finally {
await queryRunner.release();
}
}
}