saveinmed/frontend/src/services/dashboardService.ts

354 lines
12 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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?.toLowerCase() === 'admin') {
// Admin ve dados globais
stats = await this.obterEstatisticasGlobais();
} else if (userRole?.toLowerCase() === 'owner' && empresaId) {
// Owner ve dados da propria empresa
stats = await this.obterEstatisticasEmpresa(empresaId);
} else if (userRole?.toLowerCase() === 'employee' && empresaId) {
// Employee ve 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 normalizedRole = userRole?.toLowerCase()
const pedidosResponse = normalizedRole === 'admin'
? 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 = normalizedRole === 'admin'
? 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 = normalizedRole === 'admin'
? 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 normalizedRole = userRole?.toLowerCase()
const pedidosResponse = normalizedRole === 'admin'
? await pedidoService.listar()
: await pedidoService.listar();
const todosPedidos = pedidosResponse.documents || [];
// Filtrar pedidos da empresa se não for SUPERADMIN
const pedidos = normalizedRole === 'admin'
? 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 [];
}
}
}
const dashboardService = new DashboardService();
export default dashboardService;