1024 lines
29 KiB
TypeScript
1024 lines
29 KiB
TypeScript
import { PrismaClient, Decimal } from '@prisma/client';
|
|
import { v4 as uuidv4 } from 'uuid'; // Importar uuid para gerar IDs
|
|
|
|
const prisma = new PrismaClient();
|
|
|
|
export class CalculoJudicialService {
|
|
/**
|
|
* Cria um novo cálculo judicial
|
|
*/
|
|
async criarCalculo(data: {
|
|
titulo: string;
|
|
descricao?: string;
|
|
dataBase: Date;
|
|
valorBase: number;
|
|
processoId?: string;
|
|
clienteId?: string;
|
|
usuarioId: string;
|
|
}) {
|
|
try {
|
|
// Validar dados de entrada
|
|
if (!data.titulo || !data.dataBase || data.valorBase === undefined) {
|
|
throw new Error('Dados incompletos para criar cálculo');
|
|
}
|
|
|
|
// Criar cálculo no banco de dados com ID UUID explícito
|
|
const calculo = await prisma.calculoJudicial.create({
|
|
data: {
|
|
id: uuidv4(), // Gerar UUID válido
|
|
titulo: data.titulo,
|
|
descricao: data.descricao,
|
|
dataBase: data.dataBase,
|
|
dataCalculo: new Date(),
|
|
valorBase: new Decimal(data.valorBase),
|
|
valorCorrigido: new Decimal(data.valorBase),
|
|
valorFinal: new Decimal(data.valorBase),
|
|
...(data.processoId && { processo: { connect: { id: data.processoId } } }),
|
|
...(data.clienteId && { cliente: { connect: { id: data.clienteId } } }),
|
|
...(data.usuarioId && { usuario: { connect: { id: data.usuarioId } } })
|
|
}
|
|
});
|
|
|
|
// Registrar o evento de criação no histórico
|
|
await this.registrarHistorico({
|
|
calculoId: calculo.id,
|
|
usuarioId: data.usuarioId,
|
|
acao: 'CRIACAO',
|
|
descricao: 'Cálculo criado',
|
|
valorNovo: data.valorBase
|
|
});
|
|
|
|
return calculo;
|
|
} catch (error) {
|
|
console.error('Erro ao criar cálculo judicial:', error);
|
|
throw new Error(`Falha ao criar cálculo: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Busca um cálculo judicial pelo ID
|
|
*/
|
|
async buscarCalculo(id: string) {
|
|
try {
|
|
const calculo = await prisma.calculoJudicial.findUnique({
|
|
where: { id },
|
|
include: {
|
|
usuario: true,
|
|
processo: true,
|
|
cliente: true,
|
|
correcoes: true,
|
|
juros: true,
|
|
multas: true,
|
|
honorarios: true,
|
|
parcelas: true,
|
|
descontos: true,
|
|
historico: {
|
|
include: {
|
|
usuario: true
|
|
},
|
|
orderBy: {
|
|
criadoEm: 'desc'
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
if (!calculo) {
|
|
throw new Error('Cálculo não encontrado');
|
|
}
|
|
|
|
return calculo;
|
|
} catch (error) {
|
|
console.error('Erro ao buscar cálculo:', error);
|
|
throw new Error(`Falha ao buscar cálculo: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adiciona correção monetária ao cálculo
|
|
*/
|
|
async adicionarCorrecaoMonetaria(data: {
|
|
calculoId: string;
|
|
indice: string;
|
|
dataInicial: Date;
|
|
dataFinal?: Date;
|
|
valorOriginal: number;
|
|
usuarioId: string;
|
|
}) {
|
|
try {
|
|
// Validar dados
|
|
if (!data.calculoId || !data.indice || !data.dataInicial || data.valorOriginal === undefined) {
|
|
throw new Error('Dados incompletos para adicionar correção monetária');
|
|
}
|
|
|
|
// Verificar se o cálculo existe e não está finalizado
|
|
const calculo = await prisma.calculoJudicial.findUnique({
|
|
where: { id: data.calculoId }
|
|
});
|
|
|
|
if (!calculo) {
|
|
throw new Error('Cálculo não encontrado');
|
|
}
|
|
|
|
if (calculo.status === 'FINALIZADO') {
|
|
throw new Error('Não é possível modificar um cálculo finalizado');
|
|
}
|
|
|
|
// Calcular o fator de correção
|
|
const fatorCorrecao = await this.calcularFatorCorrecao({
|
|
indice: data.indice,
|
|
dataInicial: data.dataInicial,
|
|
dataFinal: data.dataFinal || new Date()
|
|
});
|
|
|
|
// Calcular valor corrigido
|
|
const valorCorrigido = new Decimal(data.valorOriginal).mul(fatorCorrecao);
|
|
|
|
// Criar registro de correção monetária
|
|
const correcao = await prisma.correcaoMonetaria.create({
|
|
data: {
|
|
id: uuidv4(), // Gerar UUID válido
|
|
calculoId: data.calculoId,
|
|
indice: data.indice,
|
|
dataInicial: data.dataInicial,
|
|
dataFinal: data.dataFinal || new Date(),
|
|
valorOriginal: new Decimal(data.valorOriginal),
|
|
valorCorrigido,
|
|
fatorCorrecao
|
|
}
|
|
});
|
|
|
|
// Atualizar o valor corrigido do cálculo
|
|
await this.atualizarValorCalculo(data.calculoId);
|
|
|
|
// Registrar no histórico
|
|
await this.registrarHistorico({
|
|
calculoId: data.calculoId,
|
|
usuarioId: data.usuarioId,
|
|
acao: 'ATUALIZACAO',
|
|
descricao: `Correção monetária adicionada: ${data.indice}`,
|
|
valorNovo: valorCorrigido.toNumber(),
|
|
metadados: {
|
|
correcaoId: correcao.id,
|
|
indice: data.indice,
|
|
dataInicial: data.dataInicial,
|
|
dataFinal: data.dataFinal || new Date(),
|
|
fatorCorrecao: fatorCorrecao.toNumber()
|
|
}
|
|
});
|
|
|
|
return correcao;
|
|
} catch (error) {
|
|
console.error('Erro ao adicionar correção monetária:', error);
|
|
throw new Error(`Falha ao adicionar correção monetária: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adiciona juros ao cálculo
|
|
*/
|
|
async adicionarJuros(data: {
|
|
calculoId: string;
|
|
tipo: string;
|
|
taxa: number;
|
|
periodicidade: string;
|
|
natureza: string;
|
|
dataInicial: Date;
|
|
dataFinal?: Date;
|
|
valorBase: number;
|
|
usuarioId: string;
|
|
}) {
|
|
try {
|
|
// Validar dados
|
|
if (!data.calculoId || !data.tipo || data.taxa === undefined || !data.dataInicial) {
|
|
throw new Error('Dados incompletos para adicionar juros');
|
|
}
|
|
|
|
// Verificar se o cálculo existe e não está finalizado
|
|
const calculo = await prisma.calculoJudicial.findUnique({
|
|
where: { id: data.calculoId }
|
|
});
|
|
|
|
if (!calculo) {
|
|
throw new Error('Cálculo não encontrado');
|
|
}
|
|
|
|
if (calculo.status === 'FINALIZADO') {
|
|
throw new Error('Não é possível modificar um cálculo finalizado');
|
|
}
|
|
|
|
// Calcular valor dos juros
|
|
const valorJuros = this.calcularJuros(
|
|
data.valorBase,
|
|
data.taxa,
|
|
data.tipo,
|
|
data.dataInicial,
|
|
data.dataFinal || new Date()
|
|
);
|
|
|
|
// Criar registro de juros
|
|
const juros = await prisma.juroCalculo.create({
|
|
data: {
|
|
id: uuidv4(), // Gerar UUID válido
|
|
calculoId: data.calculoId,
|
|
tipo: data.tipo,
|
|
taxa: new Decimal(data.taxa),
|
|
periodicidade: data.periodicidade,
|
|
natureza: data.natureza,
|
|
dataInicial: data.dataInicial,
|
|
dataFinal: data.dataFinal || new Date(),
|
|
valorBase: new Decimal(data.valorBase),
|
|
valorJuros: new Decimal(valorJuros)
|
|
}
|
|
});
|
|
|
|
// Atualizar o valor final do cálculo
|
|
await this.atualizarValorCalculo(data.calculoId);
|
|
|
|
// Registrar no histórico
|
|
await this.registrarHistorico({
|
|
calculoId: data.calculoId,
|
|
usuarioId: data.usuarioId,
|
|
acao: 'ATUALIZACAO',
|
|
descricao: `Juros adicionados: ${data.tipo} ${data.taxa * 100}% ${data.periodicidade}`,
|
|
valorNovo: valorJuros,
|
|
metadados: {
|
|
juroId: juros.id,
|
|
tipo: data.tipo,
|
|
taxa: data.taxa,
|
|
dataInicial: data.dataInicial,
|
|
dataFinal: data.dataFinal || new Date()
|
|
}
|
|
});
|
|
|
|
return juros;
|
|
} catch (error) {
|
|
console.error('Erro ao adicionar juros:', error);
|
|
throw new Error(`Falha ao adicionar juros: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adiciona multa ao cálculo
|
|
*/
|
|
async adicionarMulta(data: {
|
|
calculoId: string;
|
|
tipo: string;
|
|
percentual: number;
|
|
valorBase: number;
|
|
fundamento?: string;
|
|
usuarioId: string;
|
|
}) {
|
|
try {
|
|
// Validar dados
|
|
if (!data.calculoId || !data.tipo || data.percentual === undefined) {
|
|
throw new Error('Dados incompletos para adicionar multa');
|
|
}
|
|
|
|
// Verificar se o cálculo existe e não está finalizado
|
|
const calculo = await prisma.calculoJudicial.findUnique({
|
|
where: { id: data.calculoId }
|
|
});
|
|
|
|
if (!calculo) {
|
|
throw new Error('Cálculo não encontrado');
|
|
}
|
|
|
|
if (calculo.status === 'FINALIZADO') {
|
|
throw new Error('Não é possível modificar um cálculo finalizado');
|
|
}
|
|
|
|
// Calcular valor da multa
|
|
const valorMulta = new Decimal(data.valorBase).mul(data.percentual);
|
|
|
|
// Criar registro de multa
|
|
const multa = await prisma.multaCalculo.create({
|
|
data: {
|
|
id: uuidv4(), // Gerar UUID válido
|
|
calculoId: data.calculoId,
|
|
tipo: data.tipo,
|
|
percentual: new Decimal(data.percentual),
|
|
valorBase: new Decimal(data.valorBase),
|
|
valorMulta,
|
|
fundamento: data.fundamento
|
|
}
|
|
});
|
|
|
|
// Atualizar o valor final do cálculo
|
|
await this.atualizarValorCalculo(data.calculoId);
|
|
|
|
// Registrar no histórico
|
|
await this.registrarHistorico({
|
|
calculoId: data.calculoId,
|
|
usuarioId: data.usuarioId,
|
|
acao: 'ATUALIZACAO',
|
|
descricao: `Multa adicionada: ${data.tipo} ${data.percentual * 100}%`,
|
|
valorNovo: valorMulta.toNumber(),
|
|
metadados: {
|
|
multaId: multa.id,
|
|
tipo: data.tipo,
|
|
percentual: data.percentual
|
|
}
|
|
});
|
|
|
|
return multa;
|
|
} catch (error) {
|
|
console.error('Erro ao adicionar multa:', error);
|
|
throw new Error(`Falha ao adicionar multa: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adiciona honorários ao cálculo
|
|
*/
|
|
async adicionarHonorarios(data: {
|
|
calculoId: string;
|
|
tipo: string;
|
|
percentual: number;
|
|
valorBase: number;
|
|
fundamento?: string;
|
|
usuarioId: string;
|
|
}) {
|
|
try {
|
|
// Validar dados
|
|
if (!data.calculoId || !data.tipo || data.percentual === undefined) {
|
|
throw new Error('Dados incompletos para adicionar honorários');
|
|
}
|
|
|
|
// Verificar se o cálculo existe e não está finalizado
|
|
const calculo = await prisma.calculoJudicial.findUnique({
|
|
where: { id: data.calculoId }
|
|
});
|
|
|
|
if (!calculo) {
|
|
throw new Error('Cálculo não encontrado');
|
|
}
|
|
|
|
if (calculo.status === 'FINALIZADO') {
|
|
throw new Error('Não é possível modificar um cálculo finalizado');
|
|
}
|
|
|
|
// Calcular valor dos honorários
|
|
const valorHonorario = new Decimal(data.valorBase).mul(data.percentual);
|
|
|
|
// Criar registro de honorários
|
|
const honorario = await prisma.honorarioCalculo.create({
|
|
data: {
|
|
id: uuidv4(), // Gerar UUID válido
|
|
calculoId: data.calculoId,
|
|
tipo: data.tipo,
|
|
percentual: new Decimal(data.percentual),
|
|
valorBase: new Decimal(data.valorBase),
|
|
valorHonorario,
|
|
fundamento: data.fundamento
|
|
}
|
|
});
|
|
|
|
// Atualizar o valor final do cálculo
|
|
await this.atualizarValorCalculo(data.calculoId);
|
|
|
|
// Registrar no histórico
|
|
await this.registrarHistorico({
|
|
calculoId: data.calculoId,
|
|
usuarioId: data.usuarioId,
|
|
acao: 'ATUALIZACAO',
|
|
descricao: `Honorários adicionados: ${data.tipo} ${data.percentual * 100}%`,
|
|
valorNovo: valorHonorario.toNumber(),
|
|
metadados: {
|
|
honorarioId: honorario.id,
|
|
tipo: data.tipo,
|
|
percentual: data.percentual
|
|
}
|
|
});
|
|
|
|
return honorario;
|
|
} catch (error) {
|
|
console.error('Erro ao adicionar honorários:', error);
|
|
throw new Error(`Falha ao adicionar honorários: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adiciona parcela ao cálculo
|
|
*/
|
|
async adicionarParcela(data: {
|
|
calculoId: string;
|
|
numero: number;
|
|
dataVencimento: Date;
|
|
valorOriginal: number;
|
|
usuarioId: string;
|
|
}) {
|
|
try {
|
|
// Validar dados
|
|
if (!data.calculoId || data.numero === undefined || !data.dataVencimento) {
|
|
throw new Error('Dados incompletos para adicionar parcela');
|
|
}
|
|
|
|
// Verificar se o cálculo existe e não está finalizado
|
|
const calculo = await prisma.calculoJudicial.findUnique({
|
|
where: { id: data.calculoId }
|
|
});
|
|
|
|
if (!calculo) {
|
|
throw new Error('Cálculo não encontrado');
|
|
}
|
|
|
|
if (calculo.status === 'FINALIZADO') {
|
|
throw new Error('Não é possível modificar um cálculo finalizado');
|
|
}
|
|
|
|
// Verificar se já existe uma parcela com este número
|
|
const existente = await prisma.parcelaCalculo.findFirst({
|
|
where: {
|
|
calculoId: data.calculoId,
|
|
numero: data.numero
|
|
}
|
|
});
|
|
|
|
if (existente) {
|
|
throw new Error(`Já existe uma parcela ${data.numero} para este cálculo`);
|
|
}
|
|
|
|
// Calcular valores corrigidos se a data de vencimento já passou
|
|
let valorCorrigido = new Decimal(data.valorOriginal);
|
|
let valorJuros = new Decimal(0);
|
|
let valorMulta = new Decimal(0);
|
|
const hoje = new Date();
|
|
|
|
if (data.dataVencimento < hoje) {
|
|
// Calcular correção monetária (usando INPC como padrão)
|
|
const fatorCorrecao = await this.calcularFatorCorrecao({
|
|
indice: 'INPC',
|
|
dataInicial: data.dataVencimento,
|
|
dataFinal: hoje
|
|
});
|
|
|
|
valorCorrigido = valorCorrigido.mul(fatorCorrecao);
|
|
|
|
// Calcular juros de 1% ao mês
|
|
const meses = this.calcularMesesAtraso(data.dataVencimento, hoje);
|
|
valorJuros = valorCorrigido.mul(0.01).mul(meses);
|
|
|
|
// Multa padrão de 2%
|
|
valorMulta = valorCorrigido.mul(0.02);
|
|
}
|
|
|
|
const valorTotal = valorCorrigido.add(valorJuros).add(valorMulta);
|
|
|
|
// Criar parcela
|
|
const parcela = await prisma.parcelaCalculo.create({
|
|
data: {
|
|
id: uuidv4(), // Gerar UUID válido
|
|
calculoId: data.calculoId,
|
|
numero: data.numero,
|
|
dataVencimento: data.dataVencimento,
|
|
valorOriginal: new Decimal(data.valorOriginal),
|
|
valorCorrigido,
|
|
valorJuros,
|
|
valorMulta,
|
|
valorTotal,
|
|
pago: false
|
|
}
|
|
});
|
|
|
|
// Atualizar o valor final do cálculo
|
|
await this.atualizarValorCalculo(data.calculoId);
|
|
|
|
// Registrar no histórico
|
|
await this.registrarHistorico({
|
|
calculoId: data.calculoId,
|
|
usuarioId: data.usuarioId,
|
|
acao: 'ATUALIZACAO',
|
|
descricao: `Parcela ${data.numero} adicionada`,
|
|
valorNovo: valorTotal.toNumber(),
|
|
metadados: {
|
|
parcelaId: parcela.id,
|
|
numero: data.numero,
|
|
dataVencimento: data.dataVencimento,
|
|
valorOriginal: data.valorOriginal
|
|
}
|
|
});
|
|
|
|
return parcela;
|
|
} catch (error) {
|
|
console.error('Erro ao adicionar parcela:', error);
|
|
throw new Error(`Falha ao adicionar parcela: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Registra pagamento de uma parcela
|
|
*/
|
|
async registrarPagamentoParcela(data: {
|
|
calculoId: string;
|
|
parcelaId: string;
|
|
dataPagamento: Date;
|
|
valorPago?: number;
|
|
usuarioId: string;
|
|
}) {
|
|
try {
|
|
// Validar dados
|
|
if (!data.calculoId || !data.parcelaId || !data.dataPagamento) {
|
|
throw new Error('Dados incompletos para registrar pagamento');
|
|
}
|
|
|
|
// Buscar a parcela
|
|
const parcela = await prisma.parcelaCalculo.findUnique({
|
|
where: { id: data.parcelaId }
|
|
});
|
|
|
|
if (!parcela) {
|
|
throw new Error('Parcela não encontrada');
|
|
}
|
|
|
|
if (parcela.calculoId !== data.calculoId) {
|
|
throw new Error('Parcela não pertence ao cálculo informado');
|
|
}
|
|
|
|
// Atualizar parcela como paga
|
|
const parcelaAtualizada = await prisma.parcelaCalculo.update({
|
|
where: { id: data.parcelaId },
|
|
data: {
|
|
pago: true,
|
|
dataPagamento: data.dataPagamento
|
|
}
|
|
});
|
|
|
|
// Atualizar o valor final do cálculo
|
|
await this.atualizarValorCalculo(data.calculoId);
|
|
|
|
// Registrar no histórico
|
|
await this.registrarHistorico({
|
|
calculoId: data.calculoId,
|
|
usuarioId: data.usuarioId,
|
|
acao: 'ATUALIZACAO',
|
|
descricao: `Pagamento da parcela ${parcela.numero} registrado`,
|
|
valorNovo: data.valorPago || parcela.valorTotal.toNumber(),
|
|
metadados: {
|
|
parcelaId: data.parcelaId,
|
|
valorPago: data.valorPago || parcela.valorTotal.toNumber(),
|
|
dataPagamento: data.dataPagamento
|
|
}
|
|
});
|
|
|
|
return parcelaAtualizada;
|
|
} catch (error) {
|
|
console.error('Erro ao registrar pagamento de parcela:', error);
|
|
throw new Error(`Falha ao registrar pagamento: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adiciona desconto ao cálculo
|
|
*/
|
|
async adicionarDesconto(data: {
|
|
calculoId: string;
|
|
tipo: string;
|
|
descricao?: string;
|
|
percentual?: number;
|
|
valorFixo?: number;
|
|
valorBase: number;
|
|
usuarioId: string;
|
|
}) {
|
|
try {
|
|
// Validar dados
|
|
if (!data.calculoId || !data.tipo || (data.percentual === undefined && data.valorFixo === undefined)) {
|
|
throw new Error('Dados incompletos para adicionar desconto');
|
|
}
|
|
|
|
// Verificar se o cálculo existe e não está finalizado
|
|
const calculo = await prisma.calculoJudicial.findUnique({
|
|
where: { id: data.calculoId }
|
|
});
|
|
|
|
if (!calculo) {
|
|
throw new Error('Cálculo não encontrado');
|
|
}
|
|
|
|
if (calculo.status === 'FINALIZADO') {
|
|
throw new Error('Não é possível modificar um cálculo finalizado');
|
|
}
|
|
|
|
// Calcular valor do desconto
|
|
let valorDesconto = new Decimal(0);
|
|
if (data.valorFixo !== undefined) {
|
|
valorDesconto = new Decimal(data.valorFixo);
|
|
} else if (data.percentual !== undefined) {
|
|
valorDesconto = new Decimal(data.valorBase).mul(data.percentual);
|
|
}
|
|
|
|
// Criar registro de desconto
|
|
const desconto = await prisma.descontoCalculo.create({
|
|
data: {
|
|
id: uuidv4(), // Gerar UUID válido
|
|
calculoId: data.calculoId,
|
|
tipo: data.tipo,
|
|
descricao: data.descricao,
|
|
percentual: data.percentual ? new Decimal(data.percentual) : null,
|
|
valorFixo: data.valorFixo ? new Decimal(data.valorFixo) : null,
|
|
valorBase: new Decimal(data.valorBase),
|
|
valorDesconto
|
|
}
|
|
});
|
|
|
|
// Atualizar o valor final do cálculo
|
|
await this.atualizarValorCalculo(data.calculoId);
|
|
|
|
// Registrar no histórico
|
|
await this.registrarHistorico({
|
|
calculoId: data.calculoId,
|
|
usuarioId: data.usuarioId,
|
|
acao: 'ATUALIZACAO',
|
|
descricao: `Desconto adicionado: ${data.tipo}`,
|
|
valorNovo: valorDesconto.toNumber() * -1, // Valor negativo para desconto
|
|
metadados: {
|
|
descontoId: desconto.id,
|
|
tipo: data.tipo,
|
|
percentual: data.percentual,
|
|
valorFixo: data.valorFixo
|
|
}
|
|
});
|
|
|
|
return desconto;
|
|
} catch (error) {
|
|
console.error('Erro ao adicionar desconto:', error);
|
|
throw new Error(`Falha ao adicionar desconto: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Finaliza um cálculo judicial
|
|
*/
|
|
async finalizarCalculo(id: string, usuarioId: string) {
|
|
try {
|
|
// Verificar se o cálculo existe
|
|
const calculo = await prisma.calculoJudicial.findUnique({
|
|
where: { id }
|
|
});
|
|
|
|
if (!calculo) {
|
|
throw new Error('Cálculo não encontrado');
|
|
}
|
|
|
|
if (calculo.status === 'FINALIZADO') {
|
|
throw new Error('Cálculo já está finalizado');
|
|
}
|
|
|
|
// Finalizar o cálculo
|
|
const calculoFinalizado = await prisma.calculoJudicial.update({
|
|
where: { id },
|
|
data: {
|
|
status: 'FINALIZADO',
|
|
atualizadoEm: new Date()
|
|
}
|
|
});
|
|
|
|
// Registrar no histórico
|
|
await this.registrarHistorico({
|
|
calculoId: id,
|
|
usuarioId,
|
|
acao: 'FINALIZACAO',
|
|
descricao: 'Cálculo finalizado',
|
|
valorNovo: calculo.valorFinal.toNumber()
|
|
});
|
|
|
|
return calculoFinalizado;
|
|
} catch (error) {
|
|
console.error('Erro ao finalizar cálculo:', error);
|
|
throw new Error(`Falha ao finalizar cálculo: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Lista cálculos judiciais com filtros
|
|
*/
|
|
async listarCalculos(filtros: {
|
|
titulo?: string;
|
|
status?: string;
|
|
processoId?: string;
|
|
clienteId?: string;
|
|
usuarioId?: string;
|
|
}) {
|
|
try {
|
|
const where: any = {};
|
|
|
|
if (filtros.titulo) {
|
|
where.titulo = { contains: filtros.titulo, mode: 'insensitive' };
|
|
}
|
|
|
|
if (filtros.status) {
|
|
where.status = filtros.status;
|
|
}
|
|
|
|
if (filtros.processoId) {
|
|
where.processoId = filtros.processoId;
|
|
}
|
|
|
|
if (filtros.clienteId) {
|
|
where.clienteId = filtros.clienteId;
|
|
}
|
|
|
|
if (filtros.usuarioId) {
|
|
where.usuarioId = filtros.usuarioId;
|
|
}
|
|
|
|
const calculos = await prisma.calculoJudicial.findMany({
|
|
where,
|
|
include: {
|
|
usuario: true,
|
|
processo: true,
|
|
cliente: true
|
|
},
|
|
orderBy: {
|
|
criadoEm: 'desc'
|
|
}
|
|
});
|
|
|
|
return calculos;
|
|
} catch (error) {
|
|
console.error('Erro ao listar cálculos:', error);
|
|
throw new Error(`Falha ao listar cálculos: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gera relatório do cálculo em PDF
|
|
*/
|
|
async gerarRelatorio(id: string) {
|
|
try {
|
|
// Implementar geração de PDF
|
|
const calculo = await this.buscarCalculo(id);
|
|
|
|
if (!calculo) {
|
|
throw new Error('Cálculo não encontrado');
|
|
}
|
|
|
|
// Aqui seria implementada a lógica de geração de PDF
|
|
// Por enquanto, retornaremos apenas um buffer vazio
|
|
return Buffer.from('Relatório PDF placeholder');
|
|
} catch (error) {
|
|
console.error('Erro ao gerar relatório:', error);
|
|
throw new Error(`Falha ao gerar relatório: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Exporta cálculo para Excel
|
|
*/
|
|
async exportarExcel(id: string) {
|
|
try {
|
|
// Implementar exportação para Excel
|
|
const calculo = await this.buscarCalculo(id);
|
|
|
|
if (!calculo) {
|
|
throw new Error('Cálculo não encontrado');
|
|
}
|
|
|
|
// Aqui seria implementada a lógica de exportação para Excel
|
|
// Por enquanto, retornaremos apenas um buffer vazio
|
|
return Buffer.from('Excel placeholder');
|
|
} catch (error) {
|
|
console.error('Erro ao exportar para Excel:', error);
|
|
throw new Error(`Falha ao exportar para Excel: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Calcula o fator de correção entre duas datas para um índice
|
|
*/
|
|
async calcularFatorCorrecao(data: {
|
|
indice: string;
|
|
dataInicial: Date;
|
|
dataFinal: Date;
|
|
}) {
|
|
try {
|
|
const { indice, dataInicial, dataFinal } = data;
|
|
|
|
// Obter o mês/ano das datas
|
|
const mesInicial = dataInicial.getMonth() + 1; // getMonth retorna 0-11
|
|
const anoInicial = dataInicial.getFullYear();
|
|
const mesFinal = dataFinal.getMonth() + 1;
|
|
const anoFinal = dataFinal.getFullYear();
|
|
|
|
// Buscar todos os índices necessários para o período
|
|
const indices = await prisma.indiceMonetario.findMany({
|
|
where: {
|
|
nome: indice,
|
|
OR: [
|
|
// Índices do ano inicial
|
|
{
|
|
anoReferencia: anoInicial,
|
|
mesReferencia: { gte: mesInicial }
|
|
},
|
|
// Anos intermediários (se houver)
|
|
{
|
|
anoReferencia: { gt: anoInicial, lt: anoFinal }
|
|
},
|
|
// Índices do ano final
|
|
{
|
|
anoReferencia: anoFinal,
|
|
mesReferencia: { lte: mesFinal }
|
|
}
|
|
]
|
|
},
|
|
orderBy: [
|
|
{ anoReferencia: 'asc' },
|
|
{ mesReferencia: 'asc' }
|
|
]
|
|
});
|
|
|
|
// Se não houver índices suficientes, usar uma estimativa
|
|
if (indices.length === 0) {
|
|
const mesesDiferenca = (anoFinal - anoInicial) * 12 + (mesFinal - mesInicial);
|
|
|
|
// Taxa média mensal estimada (usar 0.5% ao mês como estimativa conservadora)
|
|
const taxaMediaMensal = 0.005;
|
|
return new Decimal(Math.pow(1 + taxaMediaMensal, mesesDiferenca));
|
|
}
|
|
|
|
// Calcular o fator de correção acumulado
|
|
let fatorAcumulado = new Decimal(1);
|
|
|
|
for (const indice of indices) {
|
|
// Somar 1 ao valor do índice (ex: índice de 0.0082 vira fator de 1.0082)
|
|
const fator = new Decimal(1).add(indice.valor);
|
|
fatorAcumulado = fatorAcumulado.mul(fator);
|
|
}
|
|
|
|
return fatorAcumulado;
|
|
} catch (error) {
|
|
console.error('Erro ao calcular fator de correção:', error);
|
|
throw new Error(`Falha ao calcular fator de correção: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Calcula juros entre duas datas
|
|
*/
|
|
private calcularJuros(
|
|
valorBase: number,
|
|
taxa: number,
|
|
tipo: string,
|
|
dataInicial: Date,
|
|
dataFinal: Date
|
|
): number {
|
|
// Calcular tempo entre as datas (em meses)
|
|
const meses = this.calcularMesesAtraso(dataInicial, dataFinal);
|
|
|
|
// Juros simples: valorBase * taxa * tempo
|
|
if (tipo === 'SIMPLES') {
|
|
return valorBase * taxa * meses;
|
|
}
|
|
|
|
// Juros compostos: valorBase * ((1 + taxa) ^ tempo - 1)
|
|
if (tipo === 'COMPOSTO') {
|
|
return valorBase * (Math.pow(1 + taxa, meses) - 1);
|
|
}
|
|
|
|
return 0; // Tipo de juros não reconhecido
|
|
}
|
|
|
|
/**
|
|
* Calcula meses de atraso entre duas datas
|
|
*/
|
|
private calcularMesesAtraso(dataInicial: Date, dataFinal: Date): number {
|
|
const diferencaAnos = dataFinal.getFullYear() - dataInicial.getFullYear();
|
|
const diferencaMeses = dataFinal.getMonth() - dataInicial.getMonth();
|
|
|
|
let meses = diferencaAnos * 12 + diferencaMeses;
|
|
|
|
// Ajustar para dias (se a diferença for menos de um mês completo)
|
|
const diaInicial = dataInicial.getDate();
|
|
const diaFinal = dataFinal.getDate();
|
|
|
|
if (diaFinal < diaInicial) {
|
|
meses -= 1;
|
|
}
|
|
|
|
// Adicionar fração do mês se necessário
|
|
const diasNoMes = new Date(dataInicial.getFullYear(), dataInicial.getMonth() + 1, 0).getDate();
|
|
const fracaoDias = (diasNoMes - diaInicial + diaFinal) / diasNoMes;
|
|
|
|
return Math.max(0, meses + fracaoDias);
|
|
}
|
|
|
|
/**
|
|
* Atualiza o valor final do cálculo somando todos os componentes
|
|
*/
|
|
private async atualizarValorCalculo(calculoId: string) {
|
|
try {
|
|
// Buscar o cálculo
|
|
const calculo = await prisma.calculoJudicial.findUnique({
|
|
where: { id: calculoId },
|
|
include: {
|
|
correcoes: true,
|
|
juros: true,
|
|
multas: true,
|
|
honorarios: true,
|
|
parcelas: true,
|
|
descontos: true
|
|
}
|
|
});
|
|
|
|
if (!calculo) {
|
|
throw new Error('Cálculo não encontrado');
|
|
}
|
|
|
|
// Valor base corrigido (usar o valor da última correção ou o valor base original)
|
|
let valorCorrigido = calculo.valorBase;
|
|
|
|
if (calculo.correcoes.length > 0) {
|
|
// Ordenar correções por data
|
|
const correcoes = [...calculo.correcoes].sort((a, b) =>
|
|
new Date(b.dataFinal).getTime() - new Date(a.dataFinal).getTime()
|
|
);
|
|
|
|
// Usar o valor da correção mais recente
|
|
valorCorrigido = correcoes[0].valorCorrigido;
|
|
}
|
|
|
|
// Somar juros
|
|
let valorJuros = new Decimal(0);
|
|
for (const juro of calculo.juros) {
|
|
valorJuros = valorJuros.add(juro.valorJuros);
|
|
}
|
|
|
|
// Somar multas
|
|
let valorMultas = new Decimal(0);
|
|
for (const multa of calculo.multas) {
|
|
valorMultas = valorMultas.add(multa.valorMulta);
|
|
}
|
|
|
|
// Somar honorários
|
|
let valorHonorarios = new Decimal(0);
|
|
for (const honorario of calculo.honorarios) {
|
|
valorHonorarios = valorHonorarios.add(honorario.valorHonorario);
|
|
}
|
|
|
|
// Calcular valor das parcelas não pagas
|
|
let valorParcelas = new Decimal(0);
|
|
for (const parcela of calculo.parcelas) {
|
|
if (!parcela.pago) {
|
|
valorParcelas = valorParcelas.add(parcela.valorTotal);
|
|
}
|
|
}
|
|
|
|
// Subtrair descontos
|
|
let valorDescontos = new Decimal(0);
|
|
for (const desconto of calculo.descontos) {
|
|
valorDescontos = valorDescontos.add(desconto.valorDesconto);
|
|
}
|
|
|
|
// Calcular valor final: Valor Corrigido + Juros + Multas + Honorários + Parcelas - Descontos
|
|
const valorFinal = valorCorrigido.add(valorJuros).add(valorMultas).add(valorHonorarios).add(valorParcelas).sub(valorDescontos);
|
|
|
|
// Atualizar o cálculo
|
|
await prisma.calculoJudicial.update({
|
|
where: { id: calculoId },
|
|
data: {
|
|
valorCorrigido,
|
|
valorFinal,
|
|
atualizadoEm: new Date()
|
|
}
|
|
});
|
|
|
|
return valorFinal;
|
|
} catch (error) {
|
|
console.error('Erro ao atualizar valor do cálculo:', error);
|
|
throw new Error(`Falha ao atualizar valor: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Registra uma entrada no histórico do cálculo
|
|
*/
|
|
async registrarHistorico(data: {
|
|
calculoId: string;
|
|
usuarioId?: string;
|
|
acao: string;
|
|
descricao: string;
|
|
valorAnterior?: number;
|
|
valorNovo?: number;
|
|
metadados?: any;
|
|
}) {
|
|
try {
|
|
return await prisma.historicoCalculo.create({
|
|
data: {
|
|
id: uuidv4(), // Gerar UUID válido
|
|
calculoId: data.calculoId,
|
|
usuarioId: data.usuarioId,
|
|
acao: data.acao,
|
|
descricao: data.descricao,
|
|
valorAnterior: data.valorAnterior !== undefined ? new Decimal(data.valorAnterior) : null,
|
|
valorNovo: data.valorNovo !== undefined ? new Decimal(data.valorNovo) : null,
|
|
metadados: data.metadados || {}
|
|
}
|
|
});
|
|
} catch (error) {
|
|
console.error('Erro ao registrar histórico:', error);
|
|
// Apenas logar o erro, não interrompe o fluxo
|
|
return null;
|
|
}
|
|
}
|
|
}
|