saveinmed/saveinmed-frontend/src/services/dashboardService.ts
Tiago Yamamoto b39caf0fd0 first commit
2025-12-17 13:58:26 -03:00

346 lines
12 KiB
TypeScript

import { produtoService } from './produtoService';
import { pedidoService } from './pedidoService';
import { empresaService } from './empresaService';
export interface DashboardStats {
medicamentosDisponiveis: number;
medicamentosVencimento: number;
pedidosRecebidos: number;
pedidosPendentes: number;
vendasMes: number;
crescimentoVendas: number; // Porcentagem
economiaGerada: number;
}
export interface AtividadeRecente {
id: string;
tipo: 'pedido' | 'produto' | 'usuario';
titulo: string;
descricao: string;
data: string;
status: 'novo' | 'atualizado' | 'pendente' | 'concluido';
}
export interface PedidoPendente {
id: string;
numero: string;
status: string;
valor: number;
comprador: string;
data: string;
}
// Tipo para representar documentos do banco
interface Documento {
$id: string;
$createdAt: string;
$updatedAt: string;
[key: string]: any;
}
class DashboardService {
/**
* Obtém estatísticas do dashboard baseadas no nível do usuário
*/
async obterEstatisticas(userRole: string, empresaId?: string): Promise<DashboardStats> {
try {
console.log(`📊 [DashboardService] Obtendo estatísticas para role: ${userRole}, empresa: ${empresaId}`);
let stats: DashboardStats = {
medicamentosDisponiveis: 0,
medicamentosVencimento: 0,
pedidosRecebidos: 0,
pedidosPendentes: 0,
vendasMes: 0,
crescimentoVendas: 0,
economiaGerada: 0,
};
if (userRole === 'SUPERADMIN') {
// Super Admin vê dados globais
stats = await this.obterEstatisticasGlobais();
} else if (userRole === 'ADMIN' && empresaId) {
// Admin vê dados da sua empresa
stats = await this.obterEstatisticasEmpresa(empresaId);
} else if (userRole === 'COLABORADOR' && empresaId) {
// Colaborador vê dados limitados da empresa
stats = await this.obterEstatisticasColaborador(empresaId);
}
console.log(`✅ [DashboardService] Estatísticas obtidas:`, stats);
return stats;
} catch (error) {
console.error('❌ [DashboardService] Erro ao obter estatísticas:', error);
throw error;
}
}
/**
* Estatísticas globais para Super Admin
*/
private async obterEstatisticasGlobais(): Promise<DashboardStats> {
try {
// Obter produtos de todas as empresas
const produtosResponse = await produtoService.listar();
const produtos = produtosResponse.documents || [];
// Obter pedidos de todas as empresas
const pedidosResponse = await pedidoService.listar();
const pedidos = pedidosResponse.documents || [];
// Calcular medicamentos próximos ao vencimento (próximos 30 dias)
const dataLimite = new Date();
dataLimite.setDate(dataLimite.getDate() + 30);
const medicamentosVencimento = produtos.filter((produto: Documento) => {
if (produto['data-vencimento']) {
const dataVencimento = new Date(produto['data-vencimento']);
return dataVencimento <= dataLimite;
}
return false;
}).length;
// Calcular pedidos pendentes
const pedidosPendentes = pedidos.filter((pedido: Documento) =>
['pendente', 'aguardando_aprovacao'].includes(pedido.status?.toLowerCase())
).length;
// Calcular vendas do mês atual
const inicioMes = new Date();
inicioMes.setDate(1);
inicioMes.setHours(0, 0, 0, 0);
const vendasMes = pedidos.filter((pedido: Documento) => {
const dataPedido = new Date(pedido.$createdAt);
return dataPedido >= inicioMes && pedido.status === 'concluido';
}).length;
// Calcular economia gerada (valor total dos produtos vendidos)
const economiaGerada = pedidos
.filter((pedido: Documento) => pedido.status === 'concluido')
.reduce((total: number, pedido: Documento) => total + (pedido['valor-total'] || 0), 0);
return {
medicamentosDisponiveis: produtos.length,
medicamentosVencimento,
pedidosRecebidos: pedidos.length,
pedidosPendentes,
vendasMes,
crescimentoVendas: 25, // Calcular baseado no mês anterior
economiaGerada,
};
} catch (error) {
console.error('❌ [DashboardService] Erro nas estatísticas globais:', error);
throw error;
}
}
/**
* Estatísticas da empresa para Admin
*/
private async obterEstatisticasEmpresa(empresaId: string): Promise<DashboardStats> {
try {
// Obter produtos da empresa
const produtosResponse = await produtoService.listarPorEmpresa(empresaId);
const produtos = produtosResponse.documents || [];
// Obter pedidos da empresa (vendas e compras)
const pedidosResponse = await pedidoService.listar();
const todosPedidos = pedidosResponse.documents || [];
// Filtrar pedidos relacionados à empresa
const pedidos = todosPedidos.filter((pedido: Documento) =>
pedido.vendedor?.includes(empresaId) || pedido.comprador === empresaId
);
// Calcular medicamentos próximos ao vencimento
const dataLimite = new Date();
dataLimite.setDate(dataLimite.getDate() + 30);
const medicamentosVencimento = produtos.filter((produto: Documento) => {
if (produto['data-vencimento']) {
const dataVencimento = new Date(produto['data-vencimento']);
return dataVencimento <= dataLimite;
}
return false;
}).length;
// Filtrar pedidos recebidos (onde a empresa é vendedora)
const pedidosRecebidos = pedidos.filter((pedido: Documento) =>
pedido.vendedor && pedido.vendedor.includes(empresaId)
);
const pedidosPendentes = pedidosRecebidos.filter((pedido: Documento) =>
['pendente', 'aguardando_aprovacao'].includes(pedido.status?.toLowerCase())
).length;
// Calcular vendas do mês
const inicioMes = new Date();
inicioMes.setDate(1);
inicioMes.setHours(0, 0, 0, 0);
const vendasMes = pedidosRecebidos.filter((pedido: Documento) => {
const dataPedido = new Date(pedido.$createdAt);
return dataPedido >= inicioMes && pedido.status === 'concluido';
}).length;
// Calcular economia gerada pela empresa
const economiaGerada = pedidosRecebidos
.filter((pedido: Documento) => pedido.status === 'concluido')
.reduce((total: number, pedido: Documento) => total + (pedido['valor-total'] || 0), 0);
return {
medicamentosDisponiveis: produtos.length,
medicamentosVencimento,
pedidosRecebidos: pedidosRecebidos.length,
pedidosPendentes,
vendasMes,
crescimentoVendas: 15, // Calcular baseado no mês anterior
economiaGerada,
};
} catch (error) {
console.error('❌ [DashboardService] Erro nas estatísticas da empresa:', error);
throw error;
}
}
/**
* Estatísticas limitadas para Colaborador
*/
private async obterEstatisticasColaborador(empresaId: string): Promise<DashboardStats> {
try {
// Colaboradores veem apenas estatísticas básicas da empresa
const produtosResponse = await produtoService.listarPorEmpresa(empresaId);
const produtos = produtosResponse.documents || [];
// Medicamentos próximos ao vencimento
const dataLimite = new Date();
dataLimite.setDate(dataLimite.getDate() + 30);
const medicamentosVencimento = produtos.filter((produto: Documento) => {
if (produto['data-vencimento']) {
const dataVencimento = new Date(produto['data-vencimento']);
return dataVencimento <= dataLimite;
}
return false;
}).length;
return {
medicamentosDisponiveis: produtos.length,
medicamentosVencimento,
pedidosRecebidos: 0, // Colaboradores não veem pedidos
pedidosPendentes: 0,
vendasMes: 0,
crescimentoVendas: 0,
economiaGerada: 0,
};
} catch (error) {
console.error('❌ [DashboardService] Erro nas estatísticas do colaborador:', error);
throw error;
}
}
/**
* Obtém atividades recentes
*/
async obterAtividadesRecentes(userRole: string, empresaId?: string, limit: number = 5): Promise<AtividadeRecente[]> {
try {
console.log(`📋 [DashboardService] Obtendo atividades recentes para role: ${userRole}`);
const atividades: AtividadeRecente[] = [];
// Obter pedidos recentes
const pedidosResponse = userRole === 'SUPERADMIN'
? await pedidoService.listar(1, limit)
: await pedidoService.listar(1, limit);
const todosPedidos = pedidosResponse.documents || [];
// Filtrar pedidos da empresa se não for SUPERADMIN
const pedidos = userRole === 'SUPERADMIN'
? todosPedidos
: todosPedidos.filter((pedido: any) =>
pedido.vendedor?.includes(empresaId!) || pedido.comprador === empresaId!
);
// Converter pedidos em atividades
pedidos.forEach((pedido: Documento) => {
atividades.push({
id: pedido.$id,
tipo: 'pedido',
titulo: `Novo pedido recebido`,
descricao: `Pedido #${pedido.$id.substring(0, 8)} - R$ ${(pedido['valor-total'] || 0).toFixed(2)}`,
data: pedido.$createdAt,
status: pedido.status === 'pendente' ? 'novo' : 'atualizado',
});
});
// Obter produtos recentemente atualizados
const produtosResponse = userRole === 'SUPERADMIN'
? await produtoService.listar(1, limit)
: await produtoService.listarPorEmpresa(empresaId!, 1, limit);
const produtos = produtosResponse.documents || []; // Converter produtos em atividades
produtos.slice(0, 2).forEach((produto: Documento) => {
atividades.push({
id: produto.$id,
tipo: 'produto',
titulo: `Produto atualizado`,
descricao: produto.nome || `Produto ${produto.$id.substring(0, 8)}`,
data: produto.$updatedAt,
status: 'atualizado',
});
});
// Ordenar por data mais recente
atividades.sort((a, b) => new Date(b.data).getTime() - new Date(a.data).getTime());
return atividades.slice(0, limit);
} catch (error) {
console.error('❌ [DashboardService] Erro ao obter atividades recentes:', error);
return [];
}
}
/**
* Obtém pedidos pendentes
*/
async obterPedidosPendentes(userRole: string, empresaId?: string, limit: number = 5): Promise<PedidoPendente[]> {
try {
console.log(`📦 [DashboardService] Obtendo pedidos pendentes para role: ${userRole}`);
const pedidosResponse = userRole === 'SUPERADMIN'
? await pedidoService.listar()
: await pedidoService.listar();
const todosPedidos = pedidosResponse.documents || [];
// Filtrar pedidos da empresa se não for SUPERADMIN
const pedidos = userRole === 'SUPERADMIN'
? todosPedidos
: todosPedidos.filter((pedido: any) =>
pedido.vendedor?.includes(empresaId!) || pedido.comprador === empresaId!
);
// Filtrar apenas pedidos pendentes
const pedidosPendentes = pedidos
.filter((pedido: Documento) => ['pendente', 'aguardando_aprovacao'].includes(pedido.status?.toLowerCase()))
.slice(0, limit)
.map((pedido: Documento) => ({
id: pedido.$id,
numero: `#${pedido.$id.substring(0, 8)}`,
status: pedido.status,
valor: pedido['valor-total'] || 0,
comprador: pedido.comprador || 'N/A',
data: pedido.$createdAt,
}));
return pedidosPendentes;
} catch (error) {
console.error('❌ [DashboardService] Erro ao obter pedidos pendentes:', error);
return [];
}
}
}
export default new DashboardService();