Primeiro commit

This commit is contained in:
2025-10-14 14:04:17 -03:00
commit 33d8645eb4
109 changed files with 55424 additions and 0 deletions

127
scripts/deploy-local.sh Executable file
View File

@@ -0,0 +1,127 @@
#!/bin/bash
# 🚀 Script de Deploy Local - Liberi Kids
# Execute: chmod +x scripts/deploy-local.sh && ./scripts/deploy-local.sh
echo "🚀 Iniciando deploy local do Liberi Kids..."
# Cores para output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Função para log colorido
log() {
echo -e "${GREEN}[INFO]${NC} $1"
}
warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Verificar se Node.js está instalado
if ! command -v node &> /dev/null; then
error "Node.js não encontrado. Instale Node.js 18+ primeiro."
exit 1
fi
# Verificar versão do Node.js
NODE_VERSION=$(node -v | cut -d'v' -f2 | cut -d'.' -f1)
if [ "$NODE_VERSION" -lt 18 ]; then
error "Node.js versão 18+ é necessária. Versão atual: $(node -v)"
exit 1
fi
log "Node.js $(node -v) encontrado ✓"
# Instalar dependências do servidor
log "Instalando dependências do servidor..."
npm install
if [ $? -ne 0 ]; then
error "Falha ao instalar dependências do servidor"
exit 1
fi
# Entrar na pasta do cliente
cd client
# Instalar dependências do cliente
log "Instalando dependências do frontend..."
npm install
if [ $? -ne 0 ]; then
error "Falha ao instalar dependências do frontend"
exit 1
fi
# Fazer build do frontend
log "Fazendo build do frontend..."
npm run build
if [ $? -ne 0 ]; then
error "Falha no build do frontend"
exit 1
fi
# Voltar para pasta raiz
cd ..
# Verificar se arquivo .env existe
if [ ! -f ".env" ]; then
warn "Arquivo .env não encontrado. Criando exemplo..."
cat > .env << EOF
# Configurações do Supabase
SUPABASE_URL=https://seu-projeto.supabase.co
SUPABASE_ANON_KEY=sua_chave_anonima_aqui
# Configurações do servidor
NODE_ENV=production
PORT=5000
EOF
warn "Configure o arquivo .env com suas credenciais do Supabase!"
echo "Edite o arquivo .env antes de continuar."
exit 1
fi
# Verificar se PM2 está instalado
if ! command -v pm2 &> /dev/null; then
log "PM2 não encontrado. Instalando PM2..."
npm install -g pm2
fi
# Parar processo anterior se existir
pm2 delete liberi-kids 2>/dev/null || true
# Iniciar aplicação com PM2
log "Iniciando aplicação com PM2..."
pm2 start server-supabase.js --name "liberi-kids" --env production
# Configurar PM2 para iniciar automaticamente
log "Configurando PM2 para inicialização automática..."
pm2 startup
pm2 save
# Status final
log "Deploy concluído com sucesso! 🎉"
echo ""
echo -e "${BLUE}📊 Status da aplicação:${NC}"
pm2 status
echo ""
echo -e "${BLUE}🌐 Acesso:${NC}"
echo " Local: http://localhost:5000"
echo " Rede: http://$(hostname -I | awk '{print $1}'):5000"
echo ""
echo -e "${BLUE}📋 Comandos úteis:${NC}"
echo " Ver logs: pm2 logs liberi-kids"
echo " Reiniciar: pm2 restart liberi-kids"
echo " Parar: pm2 stop liberi-kids"
echo " Status: pm2 status"
echo ""
log "Aplicação rodando em produção! ✓"

126
scripts/deploy-vercel.sh Executable file
View File

@@ -0,0 +1,126 @@
#!/bin/bash
# 🚀 Script de Deploy Vercel - Liberi Kids
# Execute: chmod +x scripts/deploy-vercel.sh && ./scripts/deploy-vercel.sh
echo "☁️ Iniciando deploy no Vercel..."
# Cores para output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
log() {
echo -e "${GREEN}[INFO]${NC} $1"
}
warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Verificar se Vercel CLI está instalado
if ! command -v vercel &> /dev/null; then
log "Instalando Vercel CLI..."
npm install -g vercel
fi
# Criar arquivo vercel.json se não existir
if [ ! -f "vercel.json" ]; then
log "Criando configuração do Vercel..."
cat > vercel.json << 'EOF'
{
"version": 2,
"name": "liberi-kids-estoque",
"builds": [
{
"src": "server-supabase.js",
"use": "@vercel/node"
},
{
"src": "client/package.json",
"use": "@vercel/static-build",
"config": {
"distDir": "build"
}
}
],
"routes": [
{
"src": "/api/(.*)",
"dest": "/server-supabase.js"
},
{
"src": "/(.*)",
"dest": "/client/build/$1"
}
],
"env": {
"NODE_ENV": "production"
}
}
EOF
fi
# Criar arquivo .vercelignore se não existir
if [ ! -f ".vercelignore" ]; then
log "Criando .vercelignore..."
cat > .vercelignore << 'EOF'
node_modules
.env
.env.local
.env.development
.env.test
.env.production
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.DS_Store
.vscode
.idea
*.log
EOF
fi
# Verificar se as dependências estão instaladas
log "Verificando dependências..."
npm install
cd client
npm install
cd ..
# Fazer login no Vercel (se necessário)
log "Verificando login no Vercel..."
vercel whoami || {
log "Faça login no Vercel:"
vercel login
}
# Deploy
log "Fazendo deploy no Vercel..."
vercel --prod
if [ $? -eq 0 ]; then
log "Deploy concluído com sucesso! 🎉"
echo ""
echo -e "${BLUE}📋 Próximos passos:${NC}"
echo "1. Configure as variáveis de ambiente no dashboard do Vercel:"
echo " - SUPABASE_URL"
echo " - SUPABASE_ANON_KEY"
echo ""
echo "2. Acesse: https://vercel.com/dashboard"
echo "3. Selecione seu projeto"
echo "4. Vá em Settings > Environment Variables"
echo "5. Adicione suas variáveis do Supabase"
echo ""
echo -e "${GREEN}✓ Aplicação disponível na URL fornecida pelo Vercel${NC}"
else
error "Falha no deploy. Verifique os logs acima."
exit 1
fi

84
scripts/fix-devolucoes.js Executable file
View File

@@ -0,0 +1,84 @@
#!/usr/bin/env node
const fetch = require('node-fetch');
async function limparDevolucoesDuplicadas() {
try {
console.log('🔧 Iniciando limpeza de devoluções duplicadas...');
const response = await fetch('http://localhost:5000/api/devolucoes/limpar-duplicadas', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
});
const result = await response.json();
if (result.success) {
console.log(`${result.message}`);
console.log(`📊 Total removidas: ${result.removidas}`);
} else {
console.log('❌ Erro:', result.error);
}
} catch (error) {
console.error('❌ Erro ao limpar devoluções:', error.message);
}
}
async function verificarEstadoDevolucoes() {
try {
console.log('\n📋 Verificando estado atual das devoluções...');
const response = await fetch('http://localhost:5000/api/devolucoes');
const devolucoes = await response.json();
console.log(`📊 Total de devoluções: ${devolucoes.length}`);
// Agrupar por venda para verificar duplicatas
const porVenda = {};
devolucoes.forEach(dev => {
const key = dev.venda_id;
if (!porVenda[key]) {
porVenda[key] = [];
}
porVenda[key].push(dev);
});
console.log(`📊 Vendas com devoluções: ${Object.keys(porVenda).length}`);
// Verificar vendas com múltiplas devoluções
const vendasComMultiplas = Object.entries(porVenda)
.filter(([_, devs]) => devs.length > 1);
if (vendasComMultiplas.length > 0) {
console.log(`⚠️ Vendas com múltiplas devoluções: ${vendasComMultiplas.length}`);
vendasComMultiplas.forEach(([vendaId, devs]) => {
console.log(` - Venda ${vendaId}: ${devs.length} devoluções`);
});
} else {
console.log('✅ Nenhuma venda com múltiplas devoluções encontrada');
}
} catch (error) {
console.error('❌ Erro ao verificar devoluções:', error.message);
}
}
async function main() {
console.log('🔧 Sistema de Correção de Devoluções/Trocas - Liberi Kids');
console.log('======================================================');
await verificarEstadoDevolucoes();
await limparDevolucoesDuplicadas();
await verificarEstadoDevolucoes();
console.log('\n✅ Processo concluído!');
console.log('\n📋 Próximos passos:');
console.log('1. Teste uma devolução simples');
console.log('2. Teste uma troca de produto');
console.log('3. Verifique se o estoque está sendo atualizado corretamente');
}
main().catch(console.error);

58
scripts/fix-google-drive.sh Executable file
View File

@@ -0,0 +1,58 @@
#!/bin/bash
echo "🔧 Script de Correção Google Drive - Liberi Kids"
echo "=============================================="
echo ""
echo "📋 Checklist de Configuração:"
echo ""
echo "1. ✅ Verificar se Google Drive API está ativa"
echo " - Acesse: https://console.cloud.google.com/apis/library/drive.googleapis.com"
echo " - Clique em 'Ativar' se não estiver ativo"
echo ""
echo "2. ✅ Configurar Tela de Consentimento OAuth"
echo " - Acesse: https://console.cloud.google.com/apis/credentials/consent"
echo " - Tipo: Externo"
echo " - Nome do app: Liberi Kids - Sistema de Estoque"
echo " - Adicionar escopos: drive.file e drive.readonly"
echo ""
echo "3. 🎯 CRÍTICO: Adicionar Usuários de Teste"
echo " - Na tela de consentimento, seção 'Usuários de teste'"
echo " - Adicionar SEU EMAIL (o mesmo que vai usar para autorizar)"
echo " - Sem isso, você receberá erro de autorização"
echo ""
echo "4. ✅ Verificar Credenciais OAuth"
echo " - Acesse: https://console.cloud.google.com/apis/credentials"
echo " - URIs de redirecionamento: http://localhost:5000/auth/google-drive/callback"
echo ""
echo "5. 🔄 Testar Configuração"
echo " - Recarregar página de Configurações"
echo " - Tentar autorizar novamente"
echo " - Usar o email que foi adicionado como usuário de teste"
echo ""
echo "📞 URLs Importantes:"
echo " - Google Cloud Console: https://console.cloud.google.com/"
echo " - APIs & Services: https://console.cloud.google.com/apis/"
echo " - OAuth Consent: https://console.cloud.google.com/apis/credentials/consent"
echo " - Credentials: https://console.cloud.google.com/apis/credentials"
echo ""
echo "🚨 Lembre-se: Use o MESMO EMAIL em 'Usuários de teste' e na autorização!"
echo ""
# Verificar se o servidor está rodando
if curl -s http://localhost:5000/api/google-drive/status > /dev/null; then
echo "✅ Servidor está rodando"
echo "🔗 Acesse: http://localhost:3000/configuracoes"
else
echo "❌ Servidor não está rodando"
echo "Execute: npm start"
fi
echo ""
echo "Após configurar no Google Cloud Console, recarregue a página e tente novamente!"

99
scripts/init-supabase.js Normal file
View File

@@ -0,0 +1,99 @@
const supabase = require('../config/supabase');
async function initializeSupabaseTables() {
console.log('🚀 Inicializando tabelas no Supabase...');
try {
// 1. Criar tabela de fornecedores
console.log('📦 Criando tabela fornecedores...');
const { error: fornecedoresError } = await supabase.rpc('create_fornecedores_table');
if (fornecedoresError && !fornecedoresError.message.includes('already exists')) {
console.error('Erro ao criar tabela fornecedores:', fornecedoresError);
} else {
console.log('✅ Tabela fornecedores criada/verificada');
}
// 2. Criar tabela de produtos
console.log('📦 Criando tabela produtos...');
const { error: produtosError } = await supabase.rpc('create_produtos_table');
if (produtosError && !produtosError.message.includes('already exists')) {
console.error('Erro ao criar tabela produtos:', produtosError);
} else {
console.log('✅ Tabela produtos criada/verificada');
}
// 3. Criar tabela de variações de produtos
console.log('📦 Criando tabela produto_variacoes...');
const { error: variacoesError } = await supabase.rpc('create_produto_variacoes_table');
if (variacoesError && !variacoesError.message.includes('already exists')) {
console.error('Erro ao criar tabela produto_variacoes:', variacoesError);
} else {
console.log('✅ Tabela produto_variacoes criada/verificada');
}
// 4. Criar tabela de clientes
console.log('📦 Criando tabela clientes...');
const { error: clientesError } = await supabase.rpc('create_clientes_table');
if (clientesError && !clientesError.message.includes('already exists')) {
console.error('Erro ao criar tabela clientes:', clientesError);
} else {
console.log('✅ Tabela clientes criada/verificada');
}
// 5. Criar tabela de tipos de despesas
console.log('📦 Criando tabela tipos_despesas...');
const { error: tiposDespesasError } = await supabase.rpc('create_tipos_despesas_table');
if (tiposDespesasError && !tiposDespesasError.message.includes('already exists')) {
console.error('Erro ao criar tabela tipos_despesas:', tiposDespesasError);
} else {
console.log('✅ Tabela tipos_despesas criada/verificada');
}
// 6. Criar tabela de despesas
console.log('📦 Criando tabela despesas...');
const { error: despesasError } = await supabase.rpc('create_despesas_table');
if (despesasError && !despesasError.message.includes('already exists')) {
console.error('Erro ao criar tabela despesas:', despesasError);
} else {
console.log('✅ Tabela despesas criada/verificada');
}
// 7. Criar tabela de vendas
console.log('📦 Criando tabela vendas...');
const { error: vendasError } = await supabase.rpc('create_vendas_table');
if (vendasError && !vendasError.message.includes('already exists')) {
console.error('Erro ao criar tabela vendas:', vendasError);
} else {
console.log('✅ Tabela vendas criada/verificada');
}
// 8. Criar tabela de itens de venda
console.log('📦 Criando tabela venda_itens...');
const { error: vendaItensError } = await supabase.rpc('create_venda_itens_table');
if (vendaItensError && !vendaItensError.message.includes('already exists')) {
console.error('Erro ao criar tabela venda_itens:', vendaItensError);
} else {
console.log('✅ Tabela venda_itens criada/verificada');
}
console.log('🎉 Inicialização do Supabase concluída!');
// Testar conexão
const { data, error } = await supabase.from('fornecedores').select('count', { count: 'exact' });
if (error) {
console.error('❌ Erro ao testar conexão:', error);
} else {
console.log('✅ Conexão com Supabase funcionando!');
}
} catch (error) {
console.error('❌ Erro geral na inicialização:', error);
}
}
// Executar se chamado diretamente
if (require.main === module) {
initializeSupabaseTables();
}
module.exports = initializeSupabaseTables;

View File

@@ -0,0 +1,72 @@
const supabase = require('../config/supabase');
const fs = require('fs');
const path = require('path');
async function migrateDespesasToTextFields() {
console.log('🔄 Migrando tabela despesas para campos de texto livre...');
try {
// Ler o script SQL
const sqlScript = fs.readFileSync(
path.join(__dirname, '../sql/alter-despesas-text-fields.sql'),
'utf8'
);
// Dividir o script em comandos individuais
const commands = sqlScript
.split(';')
.map(cmd => cmd.trim())
.filter(cmd => cmd.length > 0 && !cmd.startsWith('--'));
console.log(`📝 Executando ${commands.length} comandos SQL...`);
// Executar cada comando
for (let i = 0; i < commands.length; i++) {
const command = commands[i];
console.log(`⚡ Executando comando ${i + 1}/${commands.length}...`);
try {
const { error } = await supabase.rpc('exec_sql', { sql_query: command });
if (error) {
console.log(`⚠️ Comando ${i + 1} com aviso:`, error.message);
} else {
console.log(`✅ Comando ${i + 1} executado com sucesso`);
}
} catch (cmdError) {
console.log(`⚠️ Erro no comando ${i + 1}:`, cmdError.message);
}
}
// Verificar se as colunas foram criadas
console.log('🔍 Verificando estrutura da tabela...');
const { data: columns, error: columnsError } = await supabase
.from('information_schema.columns')
.select('column_name')
.eq('table_name', 'despesas')
.in('column_name', ['tipo_nome', 'fornecedor_nome']);
if (columnsError) {
console.log('⚠️ Não foi possível verificar as colunas:', columnsError.message);
} else {
const columnNames = columns.map(col => col.column_name);
if (columnNames.includes('tipo_nome') && columnNames.includes('fornecedor_nome')) {
console.log('✅ Colunas tipo_nome e fornecedor_nome criadas com sucesso!');
} else {
console.log('⚠️ Algumas colunas podem não ter sido criadas:', columnNames);
}
}
console.log('🎉 Migração concluída!');
console.log('📋 Agora você pode usar campos de texto livre para Tipo de Despesa e Fornecedor');
} catch (error) {
console.error('❌ Erro durante a migração:', error);
}
}
// Executar se chamado diretamente
if (require.main === module) {
migrateDespesasToTextFields();
}
module.exports = migrateDespesasToTextFields;

View File

@@ -0,0 +1,60 @@
const { createClient } = require('@supabase/supabase-js');
require('dotenv').config();
const supabase = createClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_ANON_KEY
);
async function migratePIXFields() {
console.log('🏦 Iniciando migração dos campos PIX...');
try {
// Executar as alterações na tabela vendas
const queries = [
"ALTER TABLE vendas ADD COLUMN IF NOT EXISTS status_pagamento VARCHAR(20) DEFAULT 'pendente'",
"ALTER TABLE vendas ADD COLUMN IF NOT EXISTS data_pagamento TIMESTAMP",
"ALTER TABLE vendas ADD COLUMN IF NOT EXISTS pix_payment_id VARCHAR(100)",
"ALTER TABLE vendas ADD COLUMN IF NOT EXISTS pix_qr_code TEXT",
"ALTER TABLE vendas ADD COLUMN IF NOT EXISTS metodo_pagamento VARCHAR(20) DEFAULT 'dinheiro'"
];
for (const query of queries) {
console.log(`Executando: ${query}`);
const { error } = await supabase.rpc('exec_sql', { sql: query });
if (error) {
console.error(`Erro ao executar query: ${error.message}`);
// Continuar mesmo com erro (campo pode já existir)
} else {
console.log('✅ Query executada com sucesso');
}
}
// Criar índices
const indexes = [
"CREATE INDEX IF NOT EXISTS idx_vendas_status_pagamento ON vendas(status_pagamento)",
"CREATE INDEX IF NOT EXISTS idx_vendas_pix_payment_id ON vendas(pix_payment_id)"
];
for (const index of indexes) {
console.log(`Criando índice: ${index}`);
const { error } = await supabase.rpc('exec_sql', { sql: index });
if (error) {
console.error(`Erro ao criar índice: ${error.message}`);
} else {
console.log('✅ Índice criado com sucesso');
}
}
console.log('🎉 Migração PIX concluída com sucesso!');
} catch (error) {
console.error('❌ Erro na migração:', error);
process.exit(1);
}
}
// Executar migração
migratePIXFields();