359 lines
9.9 KiB
JavaScript
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;
|