mirror of
https://github.com/marcogll/ap_pos.git
synced 2026-01-13 13:15:16 +00:00
fix: Resolve production issues in VPS environment
- Fix toggleCategory JavaScript error by adding null checks for productsGrid - Fix product import persistence by changing from INSERT OR REPLACE to DELETE + INSERT - Add automatic default product import on server startup when database is empty - Ensure product data survives server restarts and imports 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
4
app.js
4
app.js
@@ -2300,10 +2300,10 @@ function toggleCategory(event) {
|
|||||||
categorySection.classList.toggle('collapsed');
|
categorySection.classList.toggle('collapsed');
|
||||||
|
|
||||||
if (categorySection.classList.contains('collapsed')) {
|
if (categorySection.classList.contains('collapsed')) {
|
||||||
productsGrid.style.display = 'none';
|
if (productsGrid) productsGrid.style.display = 'none';
|
||||||
toggle.textContent = '▶';
|
toggle.textContent = '▶';
|
||||||
} else {
|
} else {
|
||||||
productsGrid.style.display = 'block';
|
if (productsGrid) productsGrid.style.display = 'block';
|
||||||
toggle.textContent = '▼';
|
toggle.textContent = '▼';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
119
server.js
119
server.js
@@ -185,6 +185,14 @@ function initializeApplication() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Verificar si hay productos, si no, importar los productos por defecto
|
||||||
|
db.get("SELECT COUNT(*) as count FROM products", [], (err, row) => {
|
||||||
|
if (!err && row.count === 0) {
|
||||||
|
console.log("No products found, importing default products...");
|
||||||
|
importDefaultProducts();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Una vez completada toda la inicialización de la DB, iniciar el servidor
|
// Una vez completada toda la inicialización de la DB, iniciar el servidor
|
||||||
startServer();
|
startServer();
|
||||||
});
|
});
|
||||||
@@ -192,6 +200,67 @@ function initializeApplication() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function importDefaultProducts() {
|
||||||
|
const defaultProducts = [
|
||||||
|
// Servicios principales con orden correcto
|
||||||
|
{ name: "Extensión de Pestañas (Clean Girl)", type: "service", price: 1570, category: "Pestañas", subcategory: "Servicios", custom_price: false, sort_order: 1 },
|
||||||
|
{ name: "Extensión de Pestañas (Elegant Lashes)", type: "service", price: 950, category: "Pestañas", subcategory: "Servicios", custom_price: false, sort_order: 10 },
|
||||||
|
{ name: "Extensión de Pestañas (Mystery Lashes)", type: "service", price: 1210, category: "Pestañas", subcategory: "Servicios", custom_price: false, sort_order: 20 },
|
||||||
|
{ name: "Extensión de Pestañas (Seduction Lashes)", type: "service", price: 1580, category: "Pestañas", subcategory: "Servicios", custom_price: false, sort_order: 30 },
|
||||||
|
|
||||||
|
// Retoques agrupados
|
||||||
|
{ name: "Elegant Lashes - Retoque (1ª Semana)", type: "service", price: 320, category: "Pestañas", subcategory: "Retoques - Elegant Lashes", custom_price: false, sort_order: 11 },
|
||||||
|
{ name: "Elegant Lashes - Retoque (2ª Semana)", type: "service", price: 420, category: "Pestañas", subcategory: "Retoques - Elegant Lashes", custom_price: false, sort_order: 12 },
|
||||||
|
{ name: "Elegant Lashes - Retoque (3ª Semana)", type: "service", price: 530, category: "Pestañas", subcategory: "Retoques - Elegant Lashes", custom_price: false, sort_order: 13 },
|
||||||
|
|
||||||
|
{ name: "Mystery Lashes - Retoque (1ª Semana)", type: "service", price: 330, category: "Pestañas", subcategory: "Retoques - Mystery Lashes", custom_price: false, sort_order: 21 },
|
||||||
|
{ name: "Mystery Lashes - Retoque (2ª Semana)", type: "service", price: 430, category: "Pestañas", subcategory: "Retoques - Mystery Lashes", custom_price: false, sort_order: 22 },
|
||||||
|
{ name: "Mystery Lashes - Retoque (3ª Semana)", type: "service", price: 540, category: "Pestañas", subcategory: "Retoques - Mystery Lashes", custom_price: false, sort_order: 23 },
|
||||||
|
|
||||||
|
{ name: "Seduction Lashes - Retoque (1ª Semana)", type: "service", price: 340, category: "Pestañas", subcategory: "Retoques - Seduction Lashes", custom_price: false, sort_order: 31 },
|
||||||
|
{ name: "Seduction Lashes - Retoque (2ª Semana)", type: "service", price: 440, category: "Pestañas", subcategory: "Retoques - Seduction Lashes", custom_price: false, sort_order: 32 },
|
||||||
|
{ name: "Seduction Lashes - Retoque (3ª Semana)", type: "service", price: 550, category: "Pestañas", subcategory: "Retoques - Seduction Lashes", custom_price: false, sort_order: 33 },
|
||||||
|
|
||||||
|
// Otros servicios
|
||||||
|
{ name: "Lash Lifting", type: "service", price: 740, category: "Pestañas", subcategory: "Servicios", custom_price: false, sort_order: 100 },
|
||||||
|
{ name: "Retiro de pestañas", type: "service", price: 140, category: "Pestañas", subcategory: "Servicios", custom_price: false, sort_order: 101 },
|
||||||
|
{ name: "Tinte para pestañas (Lash Lifting)", type: "service", price: 210, category: "Pestañas", subcategory: "Servicios", custom_price: false, sort_order: 102 },
|
||||||
|
|
||||||
|
// Microblading
|
||||||
|
{ name: "Retoque Vanity Brows (Microblading)", type: "service", price: 3680, category: "Microblading", subcategory: "Servicios", custom_price: false, sort_order: 200 },
|
||||||
|
{ name: "Vanity Lips", type: "service", price: 5250, category: "Microblading", subcategory: "Servicios", custom_price: false, sort_order: 201 },
|
||||||
|
{ name: "Microblading Vanity Brows", type: "service", price: 5250, category: "Microblading", subcategory: "Servicios", custom_price: false, sort_order: 202 },
|
||||||
|
{ name: "Powder Brows", type: "service", price: 3680, category: "Microblading", subcategory: "Servicios", custom_price: false, sort_order: 203 },
|
||||||
|
|
||||||
|
// Nail Art
|
||||||
|
{ name: "Nail Art", type: "service", price: null, category: "Uñas", subcategory: "Servicios", custom_price: true, sort_order: 300 }
|
||||||
|
];
|
||||||
|
|
||||||
|
const stmt = db.prepare(`INSERT INTO products
|
||||||
|
(name, type, price, category, subcategory, custom_price, sort_order) VALUES (?, ?, ?, ?, ?, ?, ?)`);
|
||||||
|
|
||||||
|
defaultProducts.forEach(product => {
|
||||||
|
stmt.run([
|
||||||
|
product.name,
|
||||||
|
product.type,
|
||||||
|
product.price,
|
||||||
|
product.category,
|
||||||
|
product.subcategory,
|
||||||
|
product.custom_price ? 1 : 0,
|
||||||
|
product.sort_order
|
||||||
|
], function(err) {
|
||||||
|
if (err) {
|
||||||
|
console.error(`Error inserting product ${product.name}:`, err.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
stmt.finalize(function(err) {
|
||||||
|
if (!err) {
|
||||||
|
console.log(`✅ Default products imported successfully (${defaultProducts.length} products)`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function startServer() {
|
function startServer() {
|
||||||
// --- SETUP & AUTH MIDDLEWARE ---
|
// --- SETUP & AUTH MIDDLEWARE ---
|
||||||
@@ -530,29 +599,37 @@ function startServer() {
|
|||||||
db.serialize(() => {
|
db.serialize(() => {
|
||||||
db.run("BEGIN TRANSACTION");
|
db.run("BEGIN TRANSACTION");
|
||||||
|
|
||||||
const stmt = db.prepare(`INSERT OR REPLACE INTO products
|
// Primero limpiar productos existentes para evitar duplicados
|
||||||
(name, type, price, category, subcategory, custom_price, sort_order) VALUES (?, ?, ?, ?, ?, ?, ?)`);
|
db.run("DELETE FROM products WHERE 1=1", function(deleteErr) {
|
||||||
|
if (deleteErr) {
|
||||||
products.forEach(product => {
|
|
||||||
stmt.run([
|
|
||||||
product.name,
|
|
||||||
product.type || 'service',
|
|
||||||
product.price || null,
|
|
||||||
product.category || null,
|
|
||||||
product.subcategory || null,
|
|
||||||
product.custom_price ? 1 : 0,
|
|
||||||
product.sort_order || 0
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
stmt.finalize();
|
|
||||||
|
|
||||||
db.run("COMMIT", function(err) {
|
|
||||||
if (err) {
|
|
||||||
db.run("ROLLBACK");
|
db.run("ROLLBACK");
|
||||||
return res.status(500).json({ error: err.message });
|
return res.status(500).json({ error: deleteErr.message });
|
||||||
}
|
}
|
||||||
res.json({ message: 'Products imported successfully', count: products.length });
|
|
||||||
|
const stmt = db.prepare(`INSERT INTO products
|
||||||
|
(name, type, price, category, subcategory, custom_price, sort_order) VALUES (?, ?, ?, ?, ?, ?, ?)`);
|
||||||
|
|
||||||
|
products.forEach(product => {
|
||||||
|
stmt.run([
|
||||||
|
product.name,
|
||||||
|
product.type || 'service',
|
||||||
|
product.price || null,
|
||||||
|
product.category || null,
|
||||||
|
product.subcategory || null,
|
||||||
|
product.custom_price ? 1 : 0,
|
||||||
|
product.sort_order || 0
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
stmt.finalize();
|
||||||
|
|
||||||
|
db.run("COMMIT", function(commitErr) {
|
||||||
|
if (commitErr) {
|
||||||
|
db.run("ROLLBACK");
|
||||||
|
return res.status(500).json({ error: commitErr.message });
|
||||||
|
}
|
||||||
|
res.json({ message: 'Products imported successfully', count: products.length });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user