// Script para Google Sheets con visor 3D interactivo y gestión de productos/pedidos // Hojas: "Productos" y "Pedidos" // Variables globales var productosSheet = "Productos"; var pedidosSheet = "Pedidos"; var productosData = []; var stlFiles = {}; var currentColor = "#000000"; var currentModel = null; // Inicializar al abrir el documento function onOpen() { var ui = SpreadsheetApp.getUi(); ui.createMenu('3D Viewer') .addItem('Agregar al carrito', 'addToCart') .addSeparator() .addItem('Limpiar carrito', 'clearCart') .addToUi(); // Cargar datos de productos loadProducts(); // Inicializar visor 3D init3DViewer(); } // Cargar productos desde la hoja de cálculo function loadProducts() { var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(productosSheet); if (!sheet) return; var data = sheet.getDataRange().getValues(); productosData = []; for (var i = 1; i < data.length; i++) { if (data[i][0] && data[i][1]) { productosData.push({ nombre: data[i][0], precio: data[i][1], vida: data[i][2], inventario: data[i][3], id: data[i][4] }); } } Logger.log('Productos cargados: ' + productosData.length); } // Inicializar visor 3D function init3DViewer() { // Crear HTML para el visor var html = HtmlService.createHtmlOutputFromFile('viewer') .setWidth(400) .setHeight(400); SpreadsheetApp.getUi().showModelessDialog(html, 'Visor 3D'); } // Función para agregar al carrito function addToCart(productName, quantity, client) { // Buscar el producto var product = productosData.find(p => p.nombre.toLowerCase() === productName.toLowerCase() ); if (!product) { SpreadsheetApp.getUi().alert('Producto no encontrado: ' + productName); return; } if (product.inventario <= 0) { SpreadsheetApp.getUi().alert('Producto sin inventario: ' + productName); return; } // Agregar a la hoja de pedidos var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(pedidosSheet); if (!sheet) { SpreadsheetApp.getUi().alert('Hoja de pedidos no encontrada'); return; } sheet.appendRow([ product.nombre, quantity, client, product.inventario, product.id ]); // Actualizar inventario updateInventory(product.nombre, -quantity); SpreadsheetApp.getUi().alert('Producto agregado al carrito: ' + product.nombre); } // Actualizar inventario function updateInventory(productName, quantity) { var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(productosSheet); if (!sheet) return; var data = sheet.getDataRange().getValues(); for (var i = 1; i < data.length; i++) { if (data[i][0] && data[i][0].toLowerCase() === productName.toLowerCase()) { var currentInv = parseInt(data[i][3]) || 0; var newInv = currentInv + quantity; sheet.getRange(i+1, 4).setValue(newInv); break; } } } // Limpiar carrito (eliminar últimas filas de pedidos) function clearCart() { var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(pedidosSheet); if (!sheet) return; var lastRow = sheet.getLastRow(); if (lastRow > 1) { sheet.deleteRows(2, lastRow - 1); SpreadsheetApp.getUi().alert('Carrito limpiado'); } } // Cargar STL files (simulado - en producción conectaría con Google Drive o base de datos) function loadSTLFiles() { // Esta función simula la carga de archivos STL // En producción, conectaría con Google Drive API o base de datos stlFiles = { 'greca': 'data/stl/greca.stl', 'minimalista': 'data/stl/minimalista.stl', 'clásico': 'data/stl/clásico.stl', 'moderno': 'data/stl/moderno.stl' }; // Mapeo de ID de producto a nombre de archivo STL // En producción, esto debería venir de una tabla de base de datos o configuración stlIdMapping = { // ID: nombre_archivo 1: 'greca', 2: 'mapa_rd', 3: 'arete_greca', 4: 'arete_greca', 5: 'arete_mapa_rd', 6: 'arete_mapa_rd', 7: 'arete_bandera_rd', 8: 'arete_bandera_rd', 9: 'llavero_greca', 10: 'llavero_mapa_rd', 11: 'figura_catalogo', 12: 'llavero_bandera_rd', 13: 'llavero_bandera_rd', 14: 'cortador_game', 15: 'poley_grande_steam', 16: 'poley_peq_steam', 17: 'love_jesus', 18: 'posa_vasos', 19: 'keychain_mom', 20: 'llavero_tambor', 21: 'arete_tambor', 22: 'gato_flexible', 23: 'gancho_llaves', 24: 'gancho_llaves' }; // Mapeo de nombre de archivo STL a nombre de visualización (basado en tu lista de Sheets) stlFilenameToDisplayName = { 'greca': 'Llavero estilo Greca Grab.stl', 'mapa_rd': 'Llavero estilo Mapa RD Grab.stl', 'arete_greca': 'Arete estilo Greca peq.stl', 'arete_mapa_rd': 'Arete estilo Mapa RD.stl', 'arete_bandera_rd': 'Arete estilo Bandera RD peq.stl', 'llavero_bandera_rd': 'Llavero estilo Bandera RD Grab.stl', 'cortador_game': 'CortadorGalletasGameControl.stl', 'poley_grande_steam': 'Poleygrande STEAM.stl', 'poley_peq_steam': 'Poleypeq STEAM.stl', 'love_jesus': 'Love=Jesus.stl', 'posa_vasos': 'Posa Vasos.stl', 'keychain_mom': 'KeychainMom.stl', 'llavero_tambor': 'llavero estilo tambor.STL', 'arete_tambor': 'Arete estilo tambor.stl', 'gato_flexible': 'Gato+flexible.stl', 'gancho_llaves': 'Gancho para llaves sweet home.STL' }; // Mapeo de nombre de visualización a nombre de archivo STL displayNameToStlFilename = { 'Llavero estilo Greca Grab.stl': 'greca', 'Llavero estilo Mapa RD Grab.stl': 'mapa_rd', 'Arete estilo Greca peq.stl': 'arete_greca', 'Arete estilo Mapa RD.stl': 'arete_mapa_rd', 'Arete estilo Bandera RD peq.stl': 'arete_bandera_rd', 'Llavero estilo Bandera RD Grab.stl': 'llavero_bandera_rd', 'CortadorGalletasGameControl.stl': 'cortador_game', 'Poleygrande STEAM.stl': 'poley_grande_steam', 'Poleypeq STEAM.stl': 'poley_peq_steam', 'Love=Jesus.stl': 'love_jesus', 'Posa Vasos.stl': 'posa_vasos', 'KeychainMom.stl': 'keychain_mom', 'llavero estilo tambor.STL': 'llavero_tambor', 'Arete estilo tambor.stl': 'arete_tambor', 'Gato+flexible.stl': 'gato_flexible', 'Gancho para llaves sweet home.STL': 'gancho_llaves' }; // Mapeo de nombre base (sin variaciones) a nombre de archivo STL baseNameToStlFilename = { 'llavero estilo greca': 'llavero_greca', 'llavero estilo mapa rd': 'llavero_mapa_rd', 'arete estilo greca': 'arete_greca', 'arete estilo mapa rd': 'arete_mapa_rd', 'arete estilo bandera rd': 'arete_bandera_rd', 'llavero estilo bandera rd': 'llavero_bandera_rd', 'cortador de galletas game': 'cortador_game', 'poleygrande steam': 'poley_grande_steam', 'poleypeq steam': 'poley_peq_steam', 'llavero love=jesus': 'love_jesus', 'posa vasos': 'posa_vasos', 'keychainmom': 'keychain_mom', 'llavero estilo tambor': 'llavero_tambor', 'arete estilo tambor': 'arete_tambor', 'gato flexible': 'gato_flexible', 'gancho para llaves': 'gancho_llaves' }; Logger.log('STL files cargados: ' + Object.keys(stlFiles).length); } // Cambiar color del modelo 3D function changeColor(color) { currentColor = color; // Enviar mensaje al visor para actualizar color var app = UiApp.getActiveApplication(); if (app) { app.getElementById('modelColor').setStyleAttribute('color', color); } SpreadsheetApp.getUi().showModelessDialog( HtmlService.createHtmlOutput( '