Files
App-Estoque-LiberiKids/server.js
2025-11-29 21:31:52 -03:00

359 lines
9.9 KiB
JavaScript

const express = require('express');
const cors = require('cors');
const path = require('path');
const multer = require('multer');
const { createClient } = require('@supabase/supabase-js');
const { v4: uuidv4 } = require('uuid');
require('dotenv').config();
const app = express();
const PORT = process.env.PORT || 5000;
app.use(cors());
app.use(express.json());
app.use('/uploads', express.static('uploads'));
app.use(express.static(path.join(__dirname, 'client/build')));
// Configuração do Supabase
const supabaseUrl = 'https://ydhzylfnpqlxnzfcclla.supabase.co'
const supabaseKey = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InlkaHp5bGZucHFseG56ZmNjbGxhIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjA1NDA1NjIsImV4cCI6MjA3NjExNjU2Mn0.gIHxyAYngqkJ8z2Gt5ESYmG605vhY_LGTQB7Cjp4ZTA'
const supabase = createClient(supabaseUrl, supabaseKey)
// Configuração do Multer para upload de arquivos
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads/');
},
filename: (req, file, cb) => {
const uniqueName = `${Date.now()}-${uuidv4()}${path.extname(file.originalname)}`;
cb(null, uniqueName);
}
});
const upload = multer({
storage: storage,
fileFilter: (req, file, cb) => {
if (file.mimetype.startsWith('image/')) {
cb(null, true);
} else {
cb(new Error('Apenas imagens são permitidas!'), false);
}
},
limits: { fileSize: 5 * 1024 * 1024 } // 5MB
});
console.log('🚀 Servidor configurado para usar Supabase!')
console.log('📊 Banco de dados:', supabaseUrl)
// Rotas da API
// === PRODUTOS ===
app.get('/api/produtos', async (req, res) => {
try {
const { data: produtos, error } = await supabase
.from('produtos')
.select(`
*,
fornecedores(nome),
produto_variacoes(id, quantidade)
`)
.order('created_at', { ascending: false })
if (error) throw error
// Calcular estatísticas
const produtosComEstatisticas = produtos.map(produto => ({
...produto,
fornecedor_nome: produto.fornecedores?.nome || null,
total_variacoes: produto.produto_variacoes?.length || 0,
estoque_total: produto.produto_variacoes?.reduce((total, variacao) => total + (variacao.quantidade || 0), 0) || 0
}))
res.json(produtosComEstatisticas)
} catch (error) {
console.error('Erro ao buscar produtos:', error)
res.status(500).json({ error: error.message })
}
});
app.post('/api/produtos', upload.any(), async (req, res) => {
try {
console.log('Recebendo requisição para criar produto:', req.body);
console.log('Arquivos recebidos:', req.files ? req.files.length : 0);
const { id_produto, marca, nome, estacao, genero, fornecedor_id, valor_compra, valor_revenda, variacoes_data } = req.body;
// Validações básicas
if (!marca || !nome || !estacao || !valor_compra || !valor_revenda) {
return res.status(400).json({ error: 'Campos obrigatórios não preenchidos' });
}
// Parse das variações
let variacoes = [];
try {
if (variacoes_data) {
variacoes = JSON.parse(variacoes_data);
}
} catch (error) {
console.error('Erro ao fazer parse das variações:', error);
return res.status(400).json({ error: 'Dados de variações inválidos' });
}
if (variacoes.length === 0) {
return res.status(400).json({ error: 'Pelo menos uma variação é obrigatória' });
}
// Inserir produto no Supabase
const { data: produto, error: produtoError } = await supabase
.from('produtos')
.insert([{
id_produto,
marca,
nome,
estacao,
genero: genero || 'Unissex',
fornecedor_id: fornecedor_id || null,
valor_compra: parseFloat(valor_compra),
valor_revenda: parseFloat(valor_revenda)
}])
.select()
.single()
if (produtoError) throw produtoError
console.log('Produto inserido com sucesso, processando variações...');
// Inserir variações
const variacoesParaInserir = variacoes.map(variacao => ({
produto_id: produto.id,
tamanho: variacao.tamanho,
cor: variacao.cor,
quantidade: parseInt(variacao.quantidade)
}))
const { error: variacoesError } = await supabase
.from('produto_variacoes')
.insert(variacoesParaInserir)
if (variacoesError) throw variacoesError
console.log('Produto criado com sucesso!');
res.json({ id: produto.id, message: 'Produto criado com sucesso!' });
} catch (error) {
console.error('Erro ao criar produto:', error);
res.status(500).json({ error: error.message });
}
});
// === VARIAÇÕES DE PRODUTOS ===
app.get('/api/produtos/:id/variacoes', async (req, res) => {
try {
const { id } = req.params;
const { data: variacoes, error } = await supabase
.from('produto_variacoes')
.select('*')
.eq('produto_id', id)
.order('tamanho')
.order('cor')
if (error) throw error
res.json(variacoes)
} catch (error) {
console.error('Erro ao buscar variações:', error)
res.status(500).json({ error: error.message })
}
});
app.post('/api/produtos/:id/variacoes', async (req, res) => {
try {
const { id } = req.params;
const { tamanho, cor, quantidade } = req.body;
const { data: variacao, error } = await supabase
.from('produto_variacoes')
.insert([{
produto_id: id,
tamanho,
cor,
quantidade: parseInt(quantidade)
}])
.select()
.single()
if (error) throw error
res.json({ id: variacao.id, message: 'Variação adicionada com sucesso!' })
} catch (error) {
console.error('Erro ao criar variação:', error)
res.status(500).json({ error: error.message })
}
});
// === CLIENTES ===
app.get('/api/clientes', async (req, res) => {
try {
const { data: clientes, error } = await supabase
.from('clientes')
.select('*')
.order('nome_completo')
if (error) throw error
res.json(clientes)
} catch (error) {
console.error('Erro ao buscar clientes:', error)
res.status(500).json({ error: error.message })
}
});
app.post('/api/clientes', async (req, res) => {
try {
const { nome_completo, email, whatsapp, endereco } = req.body;
const { data: cliente, error } = await supabase
.from('clientes')
.insert([{
nome_completo,
email: email || null,
whatsapp,
endereco
}])
.select()
.single()
if (error) throw error
res.json({ id: cliente.id, message: 'Cliente cadastrado com sucesso!' })
} catch (error) {
console.error('Erro ao criar cliente:', error)
res.status(500).json({ error: error.message })
}
});
// === FORNECEDORES ===
app.get('/api/fornecedores', async (req, res) => {
try {
const { data: fornecedores, error } = await supabase
.from('fornecedores')
.select('*')
.order('nome')
if (error) throw error
res.json(fornecedores)
} catch (error) {
console.error('Erro ao buscar fornecedores:', error)
res.status(500).json({ error: error.message })
}
});
app.post('/api/fornecedores', async (req, res) => {
try {
const { nome, cnpj, telefone, email, endereco } = req.body;
const { data: fornecedor, error } = await supabase
.from('fornecedores')
.insert([{
nome,
cnpj: cnpj || null,
telefone: telefone || null,
email: email || null,
endereco: endereco || null
}])
.select()
.single()
if (error) throw error
res.json({ id: fornecedor.id, message: 'Fornecedor cadastrado com sucesso!' })
} catch (error) {
console.error('Erro ao criar fornecedor:', error)
res.status(500).json({ error: error.message })
}
});
// === TIPOS DE DESPESAS ===
app.get('/api/tipos-despesas', async (req, res) => {
try {
const { data: tipos, error } = await supabase
.from('tipos_despesa')
.select('*')
.order('nome')
if (error) throw error
res.json(tipos)
} catch (error) {
console.error('Erro ao buscar tipos de despesa:', error)
res.status(500).json({ error: error.message })
}
});
app.post('/api/tipos-despesas', async (req, res) => {
try {
const { nome } = req.body;
const { data: tipo, error } = await supabase
.from('tipos_despesa')
.insert([{ nome }])
.select()
.single()
if (error) throw error
res.json({ id: tipo.id, message: 'Tipo de despesa criado com sucesso!' })
} catch (error) {
console.error('Erro ao criar tipo de despesa:', error)
res.status(500).json({ error: error.message })
}
});
// === TESTE ===
app.get('/api/test', (req, res) => {
res.json({
message: 'API funcionando com Supabase!',
timestamp: new Date(),
database: 'Supabase'
});
});
// === DASHBOARD ===
app.get('/api/dashboard', async (req, res) => {
try {
const [
{ count: totalProdutos },
{ count: totalClientes },
{ count: totalFornecedores }
] = await Promise.all([
supabase.from('produtos').select('*', { count: 'exact', head: true }),
supabase.from('clientes').select('*', { count: 'exact', head: true }),
supabase.from('fornecedores').select('*', { count: 'exact', head: true })
])
res.json({
totalProdutos: { count: totalProdutos },
totalClientes: { count: totalClientes },
totalFornecedores: { count: totalFornecedores },
vendasMes: { count: 0, total: 0 },
estoqueTotal: { total: 0 },
despesasMes: { total: 0 }
})
} catch (error) {
console.error('Erro no dashboard:', error)
res.status(500).json({ error: error.message })
}
});
// Servir arquivos estáticos do React
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'client/build', 'index.html'));
});
// Criar diretório de uploads se não existir
const fs = require('fs');
if (!fs.existsSync('uploads')) {
fs.mkdirSync('uploads');
}
app.listen(PORT, () => {
console.log(`Servidor rodando na porta ${PORT}`);
});
module.exports = app;