636 lines
20 KiB
JavaScript
636 lines
20 KiB
JavaScript
const express = require('express');
|
|
const cors = require('cors');
|
|
const path = require('path');
|
|
const multer = require('multer');
|
|
const sqlite3 = require('sqlite3').verbose();
|
|
const { v4: uuidv4 } = require('uuid');
|
|
require('dotenv').config();
|
|
|
|
const app = express();
|
|
const PORT = process.env.PORT || 5000;
|
|
|
|
// Middleware
|
|
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 multer para upload de imagens
|
|
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
|
|
});
|
|
|
|
// Inicializar banco de dados
|
|
const db = new sqlite3.Database('./liberi_kids.db', (err) => {
|
|
if (err) {
|
|
console.error('Erro ao conectar com o banco de dados:', err.message);
|
|
} else {
|
|
console.log('Conectado ao banco de dados SQLite.');
|
|
initializeDatabase();
|
|
}
|
|
});
|
|
|
|
// Função para inicializar as tabelas
|
|
function initializeDatabase() {
|
|
// Tabela de produtos
|
|
db.run(`CREATE TABLE IF NOT EXISTS produtos (
|
|
id TEXT PRIMARY KEY,
|
|
id_produto TEXT,
|
|
marca TEXT NOT NULL,
|
|
nome TEXT NOT NULL,
|
|
estacao TEXT NOT NULL,
|
|
genero TEXT DEFAULT 'Unissex',
|
|
fornecedor_id TEXT,
|
|
valor_compra REAL NOT NULL,
|
|
valor_revenda REAL NOT NULL,
|
|
foto_principal_url TEXT,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (fornecedor_id) REFERENCES fornecedores (id)
|
|
)`);
|
|
|
|
// Tabela de variações de produtos (tamanho, cor, quantidade)
|
|
db.run(`CREATE TABLE IF NOT EXISTS produto_variacoes (
|
|
id TEXT PRIMARY KEY,
|
|
produto_id TEXT NOT NULL,
|
|
tamanho TEXT NOT NULL,
|
|
cor TEXT NOT NULL,
|
|
quantidade INTEGER NOT NULL DEFAULT 0,
|
|
foto_url TEXT,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (produto_id) REFERENCES produtos (id) ON DELETE CASCADE
|
|
)`);
|
|
|
|
// Tabela de clientes
|
|
db.run(`CREATE TABLE IF NOT EXISTS clientes (
|
|
id TEXT PRIMARY KEY,
|
|
nome_completo TEXT NOT NULL,
|
|
email TEXT,
|
|
telefone TEXT,
|
|
endereco TEXT,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
)`);
|
|
|
|
// Tabela de fornecedores
|
|
db.run(`CREATE TABLE IF NOT EXISTS fornecedores (
|
|
id TEXT PRIMARY KEY,
|
|
razao_social TEXT NOT NULL,
|
|
telefone TEXT,
|
|
whatsapp TEXT,
|
|
endereco TEXT,
|
|
email TEXT,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
)`);
|
|
|
|
// Tabela de tipos de despesas
|
|
db.run(`CREATE TABLE IF NOT EXISTS tipos_despesas (
|
|
id TEXT PRIMARY KEY,
|
|
nome TEXT NOT NULL UNIQUE,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
)`);
|
|
|
|
// Tabela de despesas
|
|
db.run(`CREATE TABLE IF NOT EXISTS despesas (
|
|
id TEXT PRIMARY KEY,
|
|
tipo_despesa_id TEXT NOT NULL,
|
|
fornecedor_id TEXT,
|
|
data DATE NOT NULL,
|
|
valor REAL NOT NULL,
|
|
descricao TEXT,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (tipo_despesa_id) REFERENCES tipos_despesas (id),
|
|
FOREIGN KEY (fornecedor_id) REFERENCES fornecedores (id)
|
|
)`);
|
|
|
|
// Tabela de vendas
|
|
db.run(`CREATE TABLE IF NOT EXISTS vendas (
|
|
id TEXT PRIMARY KEY,
|
|
cliente_id TEXT,
|
|
tipo_pagamento TEXT NOT NULL, -- 'vista' ou 'parcelado'
|
|
valor_total REAL NOT NULL,
|
|
desconto REAL DEFAULT 0,
|
|
parcelas INTEGER DEFAULT 1,
|
|
valor_parcela REAL,
|
|
data_venda DATE NOT NULL,
|
|
status TEXT DEFAULT 'concluida', -- 'concluida', 'cancelada'
|
|
observacoes TEXT,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (cliente_id) REFERENCES clientes (id)
|
|
)`);
|
|
|
|
// Tabela de itens da venda
|
|
db.run(`CREATE TABLE IF NOT EXISTS venda_itens (
|
|
id TEXT PRIMARY KEY,
|
|
venda_id TEXT NOT NULL,
|
|
produto_variacao_id TEXT NOT NULL,
|
|
quantidade INTEGER NOT NULL,
|
|
valor_unitario REAL NOT NULL,
|
|
valor_total REAL NOT NULL,
|
|
FOREIGN KEY (venda_id) REFERENCES vendas (id) ON DELETE CASCADE,
|
|
FOREIGN KEY (produto_variacao_id) REFERENCES produto_variacoes (id)
|
|
)`);
|
|
|
|
console.log('Tabelas do banco de dados inicializadas.');
|
|
}
|
|
|
|
// Rotas da API
|
|
|
|
// === PRODUTOS ===
|
|
app.get('/api/produtos', (req, res) => {
|
|
const query = `
|
|
SELECT p.*, f.razao_social as fornecedor_nome,
|
|
COUNT(pv.id) as total_variacoes,
|
|
SUM(pv.quantidade) as estoque_total
|
|
FROM produtos p
|
|
LEFT JOIN fornecedores f ON p.fornecedor_id = f.id
|
|
LEFT JOIN produto_variacoes pv ON p.id = pv.produto_id
|
|
GROUP BY p.id
|
|
ORDER BY p.created_at DESC
|
|
`;
|
|
|
|
db.all(query, [], (err, rows) => {
|
|
if (err) {
|
|
res.status(500).json({ error: err.message });
|
|
return;
|
|
}
|
|
res.json(rows);
|
|
});
|
|
});
|
|
|
|
app.post('/api/produtos', upload.any(), (req, res) => {
|
|
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;
|
|
const produtoId = uuidv4();
|
|
|
|
// 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' });
|
|
}
|
|
|
|
// Iniciar transação
|
|
db.serialize(() => {
|
|
db.run('BEGIN TRANSACTION');
|
|
|
|
// Inserir produto
|
|
const produtoQuery = `INSERT INTO produtos (id, id_produto, marca, nome, estacao, genero, fornecedor_id, valor_compra, valor_revenda)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`;
|
|
|
|
const fornecedorIdFinal = fornecedor_id && fornecedor_id !== '' ? fornecedor_id : null;
|
|
|
|
db.run(produtoQuery, [produtoId, id_produto, marca, nome, estacao, genero || 'Unissex', fornecedorIdFinal, valor_compra, valor_revenda], function(err) {
|
|
if (err) {
|
|
console.error('Erro ao inserir produto:', err);
|
|
db.run('ROLLBACK');
|
|
return res.status(500).json({ error: err.message });
|
|
}
|
|
|
|
console.log('Produto inserido com sucesso, processando variações...');
|
|
|
|
// Processar variações e fotos
|
|
let variacoesProcessadas = 0;
|
|
const totalVariacoes = variacoes.length;
|
|
|
|
if (totalVariacoes === 0) {
|
|
db.run('COMMIT');
|
|
return res.json({ id: produtoId, message: 'Produto criado com sucesso!' });
|
|
}
|
|
|
|
variacoes.forEach((variacao, varIndex) => {
|
|
const variacaoId = uuidv4();
|
|
|
|
// Inserir variação
|
|
const variacaoQuery = `INSERT INTO produto_variacoes (id, produto_id, tamanho, cor, quantidade)
|
|
VALUES (?, ?, ?, ?, ?)`;
|
|
|
|
db.run(variacaoQuery, [variacaoId, produtoId, variacao.tamanho, variacao.cor, variacao.quantidade], function(err) {
|
|
if (err) {
|
|
console.error('Erro ao inserir variação:', err);
|
|
db.run('ROLLBACK');
|
|
return res.status(500).json({ error: err.message });
|
|
}
|
|
|
|
// Processar fotos desta variação
|
|
const fotosVariacao = req.files ? req.files.filter(file =>
|
|
file.fieldname.startsWith(`variacao_${varIndex}_foto_`)
|
|
) : [];
|
|
|
|
if (fotosVariacao.length > 0) {
|
|
// Usar a primeira foto como foto_url da variação
|
|
const primeiraFoto = fotosVariacao[0];
|
|
const fotoUrl = `/uploads/${primeiraFoto.filename}`;
|
|
|
|
// Atualizar variação com a primeira foto
|
|
db.run('UPDATE produto_variacoes SET foto_url = ? WHERE id = ?', [fotoUrl, variacaoId], function(err) {
|
|
if (err) {
|
|
console.error('Erro ao atualizar foto da variação:', err);
|
|
}
|
|
});
|
|
}
|
|
|
|
variacoesProcessadas++;
|
|
console.log(`Variação processada: ${variacoesProcessadas}/${totalVariacoes}`);
|
|
|
|
if (variacoesProcessadas === totalVariacoes) {
|
|
db.run('COMMIT');
|
|
console.log('Produto criado com sucesso!');
|
|
res.json({ id: produtoId, message: 'Produto criado com sucesso!' });
|
|
}
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
app.put('/api/produtos/:id', upload.single('foto_principal'), (req, res) => {
|
|
const { id } = req.params;
|
|
const { id_produto, marca, nome, estacao, genero, fornecedor_id, valor_compra, valor_revenda } = req.body;
|
|
|
|
let query, params;
|
|
|
|
if (req.file) {
|
|
const foto_principal_url = `/uploads/${req.file.filename}`;
|
|
query = `UPDATE produtos
|
|
SET id_produto = ?, marca = ?, nome = ?, estacao = ?, genero = ?, fornecedor_id = ?, valor_compra = ?, valor_revenda = ?, foto_principal_url = ?, updated_at = CURRENT_TIMESTAMP
|
|
WHERE id = ?`;
|
|
params = [id_produto, marca, nome, estacao, genero || 'Unissex', fornecedor_id, valor_compra, valor_revenda, foto_principal_url, id];
|
|
} else {
|
|
query = `UPDATE produtos
|
|
SET id_produto = ?, marca = ?, nome = ?, estacao = ?, genero = ?, fornecedor_id = ?, valor_compra = ?, valor_revenda = ?, updated_at = CURRENT_TIMESTAMP
|
|
WHERE id = ?`;
|
|
params = [id_produto, marca, nome, estacao, genero || 'Unissex', fornecedor_id, valor_compra, valor_revenda, id];
|
|
}
|
|
|
|
db.run(query, params, function(err) {
|
|
if (err) {
|
|
res.status(500).json({ error: err.message });
|
|
return;
|
|
}
|
|
res.json({ message: 'Produto atualizado com sucesso!' });
|
|
});
|
|
});
|
|
|
|
// === VARIAÇÕES DE PRODUTOS ===
|
|
app.get('/api/produtos/:id/variacoes', (req, res) => {
|
|
const { id } = req.params;
|
|
|
|
db.all('SELECT * FROM produto_variacoes WHERE produto_id = ? ORDER BY tamanho, cor', [id], (err, rows) => {
|
|
if (err) {
|
|
res.status(500).json({ error: err.message });
|
|
return;
|
|
}
|
|
res.json(rows);
|
|
});
|
|
});
|
|
|
|
app.post('/api/produtos/:id/variacoes', upload.single('foto'), (req, res) => {
|
|
const { id } = req.params;
|
|
const { tamanho, cor, quantidade } = req.body;
|
|
const foto_url = req.file ? `/uploads/${req.file.filename}` : null;
|
|
const variacao_id = uuidv4();
|
|
|
|
const query = `INSERT INTO produto_variacoes (id, produto_id, tamanho, cor, quantidade, foto_url)
|
|
VALUES (?, ?, ?, ?, ?, ?)`;
|
|
|
|
db.run(query, [variacao_id, id, tamanho, cor, quantidade, foto_url], function(err) {
|
|
if (err) {
|
|
res.status(500).json({ error: err.message });
|
|
return;
|
|
}
|
|
res.json({ id: variacao_id, message: 'Variação adicionada com sucesso!' });
|
|
});
|
|
});
|
|
|
|
// === CLIENTES ===
|
|
app.get('/api/clientes', (req, res) => {
|
|
db.all('SELECT * FROM clientes ORDER BY nome_completo', [], (err, rows) => {
|
|
if (err) {
|
|
res.status(500).json({ error: err.message });
|
|
return;
|
|
}
|
|
res.json(rows);
|
|
});
|
|
});
|
|
|
|
app.post('/api/clientes', (req, res) => {
|
|
const { nome_completo, email, telefone, endereco } = req.body;
|
|
const id = uuidv4();
|
|
|
|
const query = `INSERT INTO clientes (id, nome_completo, email, telefone, endereco)
|
|
VALUES (?, ?, ?, ?, ?)`;
|
|
|
|
db.run(query, [id, nome_completo, email, telefone, endereco], function(err) {
|
|
if (err) {
|
|
res.status(500).json({ error: err.message });
|
|
return;
|
|
}
|
|
res.json({ id, message: 'Cliente cadastrado com sucesso!' });
|
|
});
|
|
});
|
|
|
|
// === FORNECEDORES ===
|
|
app.get('/api/fornecedores', (req, res) => {
|
|
db.all('SELECT * FROM fornecedores ORDER BY razao_social', [], (err, rows) => {
|
|
if (err) {
|
|
res.status(500).json({ error: err.message });
|
|
return;
|
|
}
|
|
res.json(rows);
|
|
});
|
|
});
|
|
|
|
app.post('/api/fornecedores', (req, res) => {
|
|
const { razao_social, telefone, whatsapp, endereco, email } = req.body;
|
|
const id = uuidv4();
|
|
|
|
const query = `INSERT INTO fornecedores (id, razao_social, telefone, whatsapp, endereco, email)
|
|
VALUES (?, ?, ?, ?, ?, ?)`;
|
|
|
|
db.run(query, [id, razao_social, telefone, whatsapp, endereco, email], function(err) {
|
|
if (err) {
|
|
res.status(500).json({ error: err.message });
|
|
return;
|
|
}
|
|
res.json({ id, message: 'Fornecedor cadastrado com sucesso!' });
|
|
});
|
|
});
|
|
|
|
// === TIPOS DE DESPESAS ===
|
|
app.get('/api/tipos-despesas', (req, res) => {
|
|
db.all('SELECT * FROM tipos_despesas ORDER BY nome', [], (err, rows) => {
|
|
if (err) {
|
|
res.status(500).json({ error: err.message });
|
|
return;
|
|
}
|
|
res.json(rows);
|
|
});
|
|
});
|
|
|
|
app.post('/api/tipos-despesas', (req, res) => {
|
|
const { nome } = req.body;
|
|
const id = uuidv4();
|
|
|
|
const query = `INSERT INTO tipos_despesas (id, nome) VALUES (?, ?)`;
|
|
|
|
db.run(query, [id, nome], function(err) {
|
|
if (err) {
|
|
res.status(500).json({ error: err.message });
|
|
return;
|
|
}
|
|
res.json({ id, message: 'Tipo de despesa criado com sucesso!' });
|
|
});
|
|
});
|
|
|
|
// === DESPESAS ===
|
|
app.get('/api/despesas', (req, res) => {
|
|
const query = `
|
|
SELECT d.*, td.nome as tipo_nome, f.razao_social as fornecedor_nome
|
|
FROM despesas d
|
|
LEFT JOIN tipos_despesas td ON d.tipo_despesa_id = td.id
|
|
LEFT JOIN fornecedores f ON d.fornecedor_id = f.id
|
|
ORDER BY d.data DESC
|
|
`;
|
|
|
|
db.all(query, [], (err, rows) => {
|
|
if (err) {
|
|
res.status(500).json({ error: err.message });
|
|
return;
|
|
}
|
|
res.json(rows);
|
|
});
|
|
});
|
|
|
|
app.post('/api/despesas', (req, res) => {
|
|
const { tipo_despesa_id, fornecedor_id, data, valor, descricao } = req.body;
|
|
const id = uuidv4();
|
|
|
|
const query = `INSERT INTO despesas (id, tipo_despesa_id, fornecedor_id, data, valor, descricao)
|
|
VALUES (?, ?, ?, ?, ?, ?)`;
|
|
|
|
db.run(query, [id, tipo_despesa_id, fornecedor_id || null, data, valor, descricao], function(err) {
|
|
if (err) {
|
|
res.status(500).json({ error: err.message });
|
|
return;
|
|
}
|
|
res.json({ id, message: 'Despesa cadastrada com sucesso!' });
|
|
});
|
|
});
|
|
|
|
app.put('/api/despesas/:id', (req, res) => {
|
|
const { id } = req.params;
|
|
const { tipo_despesa_id, fornecedor_id, data, valor, descricao } = req.body;
|
|
|
|
const query = `UPDATE despesas
|
|
SET tipo_despesa_id = ?, fornecedor_id = ?, data = ?, valor = ?, descricao = ?, updated_at = CURRENT_TIMESTAMP
|
|
WHERE id = ?`;
|
|
|
|
db.run(query, [tipo_despesa_id, fornecedor_id || null, data, valor, descricao, id], function(err) {
|
|
if (err) {
|
|
res.status(500).json({ error: err.message });
|
|
return;
|
|
}
|
|
res.json({ message: 'Despesa atualizada com sucesso!' });
|
|
});
|
|
});
|
|
|
|
app.delete('/api/despesas/:id', (req, res) => {
|
|
const { id } = req.params;
|
|
|
|
db.run('DELETE FROM despesas WHERE id = ?', [id], function(err) {
|
|
if (err) {
|
|
res.status(500).json({ error: err.message });
|
|
return;
|
|
}
|
|
res.json({ message: 'Despesa excluída com sucesso!' });
|
|
});
|
|
});
|
|
|
|
// === VENDAS ===
|
|
app.get('/api/vendas', (req, res) => {
|
|
const query = `
|
|
SELECT v.*, c.nome_completo as cliente_nome
|
|
FROM vendas v
|
|
LEFT JOIN clientes c ON v.cliente_id = c.id
|
|
ORDER BY v.data_venda DESC
|
|
`;
|
|
|
|
db.all(query, [], (err, rows) => {
|
|
if (err) {
|
|
res.status(500).json({ error: err.message });
|
|
return;
|
|
}
|
|
res.json(rows);
|
|
});
|
|
});
|
|
|
|
app.post('/api/vendas', (req, res) => {
|
|
const { cliente_id, tipo_pagamento, valor_total, desconto, parcelas, data_venda, observacoes, itens } = req.body;
|
|
const vendaId = uuidv4();
|
|
const valor_parcela = tipo_pagamento === 'parcelado' ? (valor_total - desconto) / parcelas : 0;
|
|
|
|
// Iniciar transação
|
|
db.serialize(() => {
|
|
db.run('BEGIN TRANSACTION');
|
|
|
|
// Inserir venda
|
|
const vendaQuery = `INSERT INTO vendas (id, cliente_id, tipo_pagamento, valor_total, desconto, parcelas, valor_parcela, data_venda, observacoes)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`;
|
|
|
|
db.run(vendaQuery, [vendaId, cliente_id || null, tipo_pagamento, valor_total, desconto, parcelas, valor_parcela, data_venda, observacoes], function(err) {
|
|
if (err) {
|
|
db.run('ROLLBACK');
|
|
res.status(500).json({ error: err.message });
|
|
return;
|
|
}
|
|
|
|
// Inserir itens da venda
|
|
let itemsProcessed = 0;
|
|
const totalItems = itens.length;
|
|
|
|
if (totalItems === 0) {
|
|
db.run('COMMIT');
|
|
res.json({ id: vendaId, message: 'Venda registrada com sucesso!' });
|
|
return;
|
|
}
|
|
|
|
itens.forEach((item) => {
|
|
const itemId = uuidv4();
|
|
const itemQuery = `INSERT INTO venda_itens (id, venda_id, produto_variacao_id, quantidade, valor_unitario, valor_total)
|
|
VALUES (?, ?, ?, ?, ?, ?)`;
|
|
|
|
db.run(itemQuery, [itemId, vendaId, item.produto_variacao_id, item.quantidade, item.valor_unitario, item.valor_total], function(err) {
|
|
if (err) {
|
|
db.run('ROLLBACK');
|
|
res.status(500).json({ error: err.message });
|
|
return;
|
|
}
|
|
|
|
// Atualizar estoque
|
|
const updateEstoque = `UPDATE produto_variacoes
|
|
SET quantidade = quantidade - ?
|
|
WHERE id = ?`;
|
|
|
|
db.run(updateEstoque, [item.quantidade, item.produto_variacao_id], function(err) {
|
|
if (err) {
|
|
db.run('ROLLBACK');
|
|
res.status(500).json({ error: err.message });
|
|
return;
|
|
}
|
|
|
|
itemsProcessed++;
|
|
if (itemsProcessed === totalItems) {
|
|
db.run('COMMIT');
|
|
res.json({ id: vendaId, message: 'Venda registrada com sucesso!' });
|
|
}
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
app.delete('/api/vendas/:id', (req, res) => {
|
|
const { id } = req.params;
|
|
|
|
db.run('DELETE FROM vendas WHERE id = ?', [id], function(err) {
|
|
if (err) {
|
|
res.status(500).json({ error: err.message });
|
|
return;
|
|
}
|
|
res.json({ message: 'Venda excluída com sucesso!' });
|
|
});
|
|
});
|
|
|
|
// === TESTE ===
|
|
app.get('/api/test', (req, res) => {
|
|
res.json({ message: 'API funcionando corretamente!', timestamp: new Date() });
|
|
});
|
|
|
|
// === DASHBOARD ===
|
|
app.get('/api/dashboard', (req, res) => {
|
|
const queries = {
|
|
totalProdutos: 'SELECT COUNT(*) as count FROM produtos',
|
|
totalClientes: 'SELECT COUNT(*) as count FROM clientes',
|
|
totalFornecedores: 'SELECT COUNT(*) as count FROM fornecedores',
|
|
vendasMes: `SELECT COUNT(*) as count, SUM(valor_total) as total
|
|
FROM vendas
|
|
WHERE strftime('%Y-%m', data_venda) = strftime('%Y-%m', 'now')`,
|
|
estoqueTotal: 'SELECT SUM(quantidade) as total FROM produto_variacoes',
|
|
despesasMes: `SELECT SUM(valor) as total
|
|
FROM despesas
|
|
WHERE strftime('%Y-%m', data) = strftime('%Y-%m', 'now')`
|
|
};
|
|
|
|
const results = {};
|
|
let completed = 0;
|
|
const total = Object.keys(queries).length;
|
|
|
|
Object.entries(queries).forEach(([key, query]) => {
|
|
db.get(query, [], (err, row) => {
|
|
if (err) {
|
|
results[key] = { error: err.message };
|
|
} else {
|
|
results[key] = row;
|
|
}
|
|
|
|
completed++;
|
|
if (completed === total) {
|
|
res.json(results);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
// 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;
|