¿Buscas una experiencia gastronómica en Mallorca que vaya más allá del plato? Los restaurantes con huerto propio en la isla han convertido la cocina de proximidad en una declaración de principios: cada verdura, cada hierba aromática y cada fruta llega a la mesa desde la misma tierra que rodea el comedor. Es la cadena corta en su expresión más pura, y Mallorca es uno de los mejores escenarios del Mediterráneo para vivirla.
Contenidos / Contents
La diferencia entre un restaurante con huerto y uno que simplemente compra producto local no es solo logística: es filosófica. Cuando el chef cultiva sus propios ingredientes, el menú lo dicta la tierra, no el mercado. El cocinero sabe exactamente en qué punto de maduración está cada tomate, cuándo cortar la albahaca para que conserve todo su aceite esencial y qué variedad de lechuga aguanta mejor el calor de agosto.
Este modelo de cocina de proximidad reduce drásticamente la huella de carbono del plato, elimina intermediarios y garantiza una frescura que ninguna cadena de distribución puede replicar. Para el comensal, el resultado es inmediato: sabores más intensos, texturas más vivas y una conexión real con el territorio que se percibe desde el primer bocado. Los restaurantes con huerto logran este resultado precisamente porque el ingrediente nunca abandona la finca antes de estar en el plato.
En Mallorca, la tradición agrícola —el cultivo del olivar, la huerta del Raiguer, los frutales del interior— ofrece el contexto perfecto para que este modelo florezca. No es una tendencia importada: es un regreso a cómo siempre se comió en la isla. La biodiversidad agrícola de la isla, con variedades autóctonas como el tomate ramallet, el pimiento de tap de cortí o la berenjena mallorquina, ofrece a estos chefs una paleta de ingredientes que ningún proveedor externo puede replicar. Por eso los restaurantes con huerto mallorquines tienen una autenticidad difícil de encontrar en otros destinos mediterráneos.
Uno de los grandes atractivos de los restaurantes con huerto en Mallorca es que el menú cambia con el calendario agrícola, no con las tendencias del mercado. Entender qué produce el huerto en cada época del año ayuda a elegir el mejor momento para visitar cada establecimiento.
Conocer este calendario permite anticipar qué ingredientes propios protagonizarán el menú de temporada en cada visita, y convierte la elección del mes en parte de la experiencia gastronómica. Visitar restaurantes con huerto en distintas estaciones es, en sí mismo, una forma de leer el paisaje mallorquín.
Qanat es, sin duda, uno de los restaurantes con huerto más singulares de Mallorca. Ubicado en Finca Treurer, en Algaida, en pleno Pla de Mallorca, nació del deseo de la familia Miralles Gutiérrez de abrir el paisaje, la historia y la cocina de la finca a quienes buscan una experiencia auténtica. El nombre remite a la antigua acequia árabe del siglo XII que durante generaciones abasteció de agua la finca: un guiño a la relación más primaria entre tierra y sustento.
En Qanat se trabaja casi exclusivamente con productos locales y de temporada, aprovechando el huerto y los árboles frutales de la propia finca. Verduras, hortalizas y hierbas aromáticas cultivadas a metros del comedor llegan a la cocina con una frescura imposible de conseguir de otra forma. Es el mismo aceite de oliva virgen extra que el chef José Cortés usa en Qanat para aliñar, cocinar y terminar cada plato de la carta estacional. Como restaurante con huerto integrado en una finca productiva, Qanat representa un modelo especialmente coherente.
Bajo la dirección del chef José Cortés, Qanat ofrece una cocina mallorquina de autor y sostenible. El aceite de oliva virgen extra Treurer —Arbequina, producido con aceitunas recogidas en su punto óptimo de maduración— no es un condimento más: es el hilo conductor que une el huerto, el olivar y la mesa. Una mesa con vistas al olivar y al valle de Randa, con vinos mallorquines y una cocina que respeta el calendario: así es Qanat, uno de los restaurantes con huerto más coherentes de la isla.
| Dirección | Ctra. Llucmajor–Algaida, km 5,7 — Algaida (Mallorca) |
| Reservas | +34 651 696 322 · treurer.com |
| Precio orientativo | €€€ (menú degustación) |
| Apertura | Temporada alta (consultar disponibilidad en invierno) |
| Comensales externos | Sí, con reserva previa (solo mayores de edad) |
En el interior de la isla, el restaurante Andreu Genestra representa uno de los proyectos más ambiciosos de cocina de proximidad en Mallorca. Galardonado con una estrella de la Guía Michelin y dos soles de la Guía Repsol, el chef mallorquín lleva más de una década trabajando en casa tras pasar por cocinas internacionales de referencia. Entre los restaurantes con huerto de alto nivel de las Baleares, Andreu Genestra es una referencia ineludible.
Uno de sus grandes atractivos es el amplio huerto que rodea el restaurante, que lo convierte en uno de los espacios más destacados vinculados a un restaurante de autor en las Baleares. Para sus elaboraciones, Genestra trabaja con el concepto «Mediterranean», con menús degustación que combinan alimentos locales —muchos producidos en su propio huerto, de kilómetro 0— con las recetas más tradicionales de la región. El chef ha declarado públicamente que «el huerto no es un complemento del restaurante, es su razón de ser»: una filosofía que se traduce en menús donde cada plato puede rastrearse hasta el surco concreto donde creció el ingrediente principal.
El restaurante ha recibido también la estrella verde Michelin por su compromiso con la sostenibilidad gastronómica. Este reconocimiento, que la guía reserva para los establecimientos más comprometidos con la agricultura ecológica certificada y la cadena corta, convierte a Andreu Genestra en una referencia ineludible para cualquier viajero que quiera entender cómo los restaurantes con huerto pueden alcanzar la excelencia sin renunciar a sus raíces.
| Dirección | Carretera Palma-Artà, km 49 — Capdepera (Mallorca) |
| Reservas | andreugenestra.com |
| Precio orientativo | €€€ (menú degustación) |
| Apertura | Temporada alta; consultar cierre invernal |
| Comensales externos | Sí, con reserva previa |
Si hay una chef que encarna la filosofía del ingrediente propio en Mallorca, esa es Macarena de Castro. Reconocida con estrella Michelin y con la estrella verde que premia su compromiso con la sostenibilidad, Maca de Castro está considerada un referente de la alta cocina balear y española. Su propuesta es uno de los ejemplos más puros de lo que puede conseguir un restaurante con huerto cuando la chef lo entiende como centro de su identidad.
Locavore antes de tiempo, Maca de Castro recorre la isla en búsqueda de los mejores ingredientes: la lonja del Puerto de Sóller para el caproig, el puerto de Alcúdia para el marisco, y las verduras de su propio huerto en Sa Pobla. Su menú degustación se crea cada mañana con lo que ofrece el huerto y los mejores pescados de la bahía. No hay carta fija: el huerto dicta el menú del día. La chef ha explicado en entrevistas que «los productos de Mallorca son los protagonistas de mi cocina, me inspiran y son parte de nuestra identidad» —una declaración que resume mejor que cualquier descripción editorial la esencia de este proyecto.
El menú sorpresa de degustación es creativo e inspirado en el Mediterráneo, con foco en los mejores ingredientes de temporada de Mallorca, la mayoría procedentes de subastas cercanas, pequeños productores de la isla o del huerto propio en Sa Pobla. Una propuesta que convierte cada visita en una experiencia irrepetible, porque ningún día es igual al anterior. Entre los restaurantes con huerto de la isla, el de Maca de Castro destaca por la intensidad con que el jardín cultivado se refleja en cada plato.
| Dirección | Port d’Alcúdia (Mallorca) |
| Reservas | macadecastro.com |
| Precio orientativo | €€€ (menú degustación) |
| Apertura | Temporada alta; consultar fechas exactas |
| Comensales externos | Sí, con reserva previa |
En Montuïri, en el corazón del Pla de Mallorca, el restaurante Jacaranda del hotel-resort Finca Serena ofrece una de las experiencias de cadena corta más completas de la isla. La finca cuenta con dos huertos ecológicos que proveen de verduras y aceite de sus propios olivares, en un entorno que transporta a un interior de la isla que se alimentaba de los productos de la tierra antes de que el turismo lo transformara todo. Pocos restaurantes con huerto ecológico en Mallorca pueden presumir de esta doble estructura de cultivo.
La propuesta de Jacaranda no separa el ingrediente del paisaje: comer aquí es también entender cómo era Mallorca antes de la costa, cuando cada finca era un ecosistema autosuficiente. Jacaranda es, en ese sentido, un restaurante con huerto que hace de la autosuficiencia agrícola un argumento estético y gastronómico al mismo tiempo. La barbacoa bajo las estrellas de los jueves, que se celebra en una terraza mirando a la Serra de Tramuntana, es otra de las experiencias destacadas de este hotel-restaurante.
Para quienes no se alojan en el hotel, existe la posibilidad de acceder al restaurante mediante un day pass que combina comida, spa y piscina. Una fórmula que democratiza el acceso a una experiencia gastronómica de primer nivel sin renunciar a la autenticidad de los ingredientes propios.
| Dirección | Camí de Sabor, s/n — Montuïri (Mallorca) |
| Reservas | fincaserena.com |
| Precio orientativo | €€€ (day pass disponible) |
| Apertura | Abierto todo el año (consultar periodos) |
| Comensales externos | Sí, mediante day pass o reserva de restaurante |
En Son Servera, en el levante de la isla, S’Era de Pula es uno de esos restaurantes con huerto que llevan décadas demostrando que la sostenibilidad gastronómica no es una moda reciente. El lugar es un pequeño pueblo completamente restaurado donde conviven un campo de golf, una huerta, un restaurante y un hotel. Como restaurante con huerto propio de larga trayectoria, S’Era de Pula ha construido una reputación basada en la coherencia y la constancia.
Todas las verduras son ecológicas, procedentes de un huerto situado junto al restaurante. La carta ofrece productos locales y verduras de su propia huerta, con una cocina sabrosa y muy cuidada. La cocina de proximidad aquí no es un concepto: es geografía. S’Era de Pula lleva tanto tiempo apostando por el huerto propio que bien puede considerarse uno de los precursores de esta tendencia en Mallorca.
| Dirección | Ctra. Son Servera–Capdepera, km 3 — Son Servera (Mallorca) |
| Reservas | serapula.com |
| Precio orientativo | €€ |
| Apertura | Temporada alta; consultar invierno |
| Comensales externos | Sí, abierto al público general |
Mallorca tiene condiciones excepcionales para que este modelo de restauración prospere. El clima mediterráneo permite cultivar casi todo el año; la tradición agrícola de la isla —olivares, almendros, hortalizas del Raiguer— ofrece una base varietal extraordinaria; y la demanda de turistas y residentes con interés en experiencias auténticas crea el mercado necesario para sostener proyectos de alta exigencia. Los restaurantes con huerto encuentran aquí, por tanto, un ecosistema ideal. No es casualidad que algunos de los mejores restaurantes con huerto de España se localicen precisamente en Mallorca.
En un restaurante con huerto propio, la cadena entre el cultivo y el plato se reduce a horas, no a días. Esto tiene consecuencias directas en el sabor: las vitaminas y los aromas volátiles de las hierbas aromáticas se degradan rápidamente tras la cosecha, y ningún sistema de refrigeración puede compensar ese proceso. Un tomate recogido por la mañana y servido al mediodía es un producto radicalmente distinto al que ha pasado por cámara frigorífica y transporte. Cualquier comensal que haya visitado un restaurante con huerto lo confirma desde el primer bocado.
La cocina de proximidad también permite al chef trabajar con variedades autóctonas que no tienen salida comercial en los circuitos convencionales: tomates ramallet, pimientos de tap de cortí, berenjenas mallorquinas. Ingredientes propios que definen la identidad gastronómica de la isla y que difícilmente aparecen en restaurantes que dependen de proveedores externos. Preservar esta biodiversidad agrícola es, además, un acto de conservación cultural: cada variedad local que un chef planta en su huerto es una variedad que no desaparece del paisaje mallorquín. Esta es una de las razones por las que los restaurantes con huerto en Mallorca resultan tan difíciles de replicar fuera del contexto insular.
Los restaurantes con huerto en Mallorca entienden la sostenibilidad gastronómica de forma integral. No se trata solo de cultivar: se trata de cerrar el ciclo. Los restos orgánicos vuelven al compost, el agua de riego se gestiona con criterio, las variedades locales se preservan frente a la homogeneización del mercado y los productores cercanos se integran en la red de abastecimiento cuando el huerto propio no cubre toda la demanda. Algunos establecimientos, como Andreu Genestra, han obtenido certificaciones de agricultura ecológica que avalan este compromiso más allá del discurso. Estos restaurantes con huerto certificado representan la cumbre del movimiento de sostenibilidad gastronómica en las Baleares.
Este enfoque conecta directamente con los valores del territorio mallorquín: una isla que ha aprendido a vivir de sus recursos y que encuentra en la gastronomía uno de sus mejores embajadores culturales. Comer en un restaurante con huerto propio en Mallorca es, en ese sentido, un acto de turismo responsable y de apoyo a la identidad local.
La oferta de restaurantes con huerto en Mallorca es variada, y cada establecimiento tiene un perfil diferente. Antes de reservar, conviene tener claros algunos criterios:
El aceite de oliva virgen extra Treurer, producido en la misma finca donde nació Qanat, es un buen indicador del nivel de exigencia que estos establecimientos aplican a cada ingrediente. Cuando el AOVE que aliña tus verduras proviene de los mismos olivos que ves desde la mesa, la experiencia adquiere una coherencia que va más allá de la gastronomía. Puedes conocer más sobre la finca Treurer y su historia para entender el contexto que rodea a Qanat. En este sentido, los mejores restaurantes con huerto de Mallorca comparten esa misma voluntad de coherencia total entre entorno, cultivo y cocina.
Es un establecimiento que cultiva parte o la totalidad de sus verduras, hortalizas y hierbas aromáticas en un terreno propio o vinculado directamente al restaurante. A diferencia de los restaurantes que compran producto local a proveedores externos, aquí la cadena entre el cultivo y el plato se reduce a horas, lo que garantiza una frescura y un control sobre el ingrediente imposibles de replicar de otra forma.
El interior de la isla —el Pla de Mallorca, la comarca del Raiguer y el levante— concentra la mayor densidad de restaurantes con huerto propio, ya que disponen de espacio y de una tradición agrícola sólida. Algaida, Montuïri y Son Servera son municipios de referencia, aunque también existen propuestas en el norte, como Maca de Castro en el Port d’Alcúdia.
Sí. Los restaurantes con huerto propio en Mallorca suelen tener aforos reducidos y una demanda alta, especialmente en temporada alta (junio-septiembre). Para establecimientos como Qanat de Treurer, Andreu Genestra o Maca de Castro, se recomienda reservar con un mínimo de una semana de antelación, y más en fechas especiales.
La cocina de proximidad o kilómetro 0 implica abastecerse de productores locales en un radio reducido. La cocina con ingredientes propios va un paso más allá: el restaurante cultiva directamente sus ingredientes, eliminando cualquier intermediario. Ambos modelos comparten valores de sostenibilidad gastronómica y cadena corta, pero el huerto propio ofrece un control total sobre la variedad, el punto de maduración y el método de cultivo.
En Mallorca, el aceite de oliva virgen extra es mucho más que un condimento: es el nexo entre la tierra y la cocina. En restaurantes como Qanat de Treurer, el AOVE producido en la propia finca se usa para aliñar, cocinar y terminar cada plato, convirtiéndose en el hilo conductor de toda la propuesta gastronómica. Un aceite de calidad, como el Treurer Arbequina, transforma un plato sencillo de huerto en algo verdaderamente memorable.
Reserva tu mesa en Qanat
Selecciona fecha, hora y número de comensales
Selecciona una fecha para ver los horarios disponibles
Reserva y puntualidad
Mantendremos tu mesa reservada durante 15 minutos de cortesía. Si prevés llegar más tarde, te agradeceremos que nos lo comuniques. En caso contrario, no podremos garantizar la disponibilidad de la reserva.
Cancelaciones
Las cancelaciones realizadas con menos de 24 horas de antelación no serán reembolsables en ningún caso.
Edad mínima
El acceso está permitido únicamente a mayores de 14 años.
Mascotas
Las mascotas son bienvenidas en nuestra terraza, siempre que permanezcan limpias, tranquilas, atadas y bajo la supervisión de su responsable, evitando en todo momento molestias al resto de los clientes. Nos reservamos el derecho de asignar la mesa que consideremos más adecuada. Durante la temporada de invierno, te rogamos que nos consultes antes de realizar la reserva.
Código de vestimenta
Agradecemos una vestimenta smart casual: elegante, cómoda e informal.
Convivencia
Te rogamos mantener un ambiente tranquilo, evitando alzar la voz y mostrando respeto tanto hacia los demás clientes como hacia nuestro equipo. Está permitido fumar únicamente en la zona habilitada para ello.
Restricciones alimentarias
Si tienes alguna alergia, intolerancia o restricción alimentaria, te agradeceremos que nos lo comuniques antes de tu llegada. Una vez iniciado el servicio, no podemos garantizar que sea posible realizar modificaciones en el menú.
Con el fin de preservar el ambiente y el bienestar de todos los presentes, nos reservamos el derecho de solicitar el abandono del establecimiento en caso de comportamientos que alteren la convivencia o el normal desarrollo del servicio.
Procesando...
' + flavorI18n.loadingTimes + '
'; fetch(flavorRestUrl + 'restaurants/' + flavorRestaurantId + '/available-slots?date=' + dateStr + '&guests=' + guests) .then(function(r) { return r.json(); }) .then(function(data) { if (data.success && data.data && data.data.length > 0) { var html = ''; data.data.forEach(function(slot) { var timeShort = slot.time.substring(0, 5); if (slot.available) { var cls = 'flavor-slot' + (flavorData.time === timeShort ? ' on' : ''); html += ''; } else { var reasonText = flavorI18n.notAvailable; if (slot.reason === 'capacity') reasonText = flavorI18n.capacityFull; else if (slot.reason === 'max_reservations') reasonText = flavorI18n.maxReservations; else if (slot.reason === 'min_advance') reasonText = flavorI18n.minAdvance; html += ''; } }); container.innerHTML = html; container.querySelectorAll('.flavor-slot:not(.busy)').forEach(function(b) { b.addEventListener('click', function() { flavorData.time = b.dataset.t; container.querySelectorAll('.flavor-slot').forEach(function(s) { s.classList.remove('on'); }); b.classList.add('on'); flavorCheckStep1(); }); }); } else { container.innerHTML = '' + flavorI18n.noTimesAvailable + '
'; } }) .catch(function() { container.innerHTML = '' + flavorI18n.errorLoadingTimes + '
'; }); } // ===================== // CHIPS (Guests) // ===================== document.getElementById('flavorChips').addEventListener('click', function(e) { var c = e.target.closest('.flavor-chip'); if (!c) return; flavorData.guests = parseInt(c.dataset.val); document.querySelectorAll('.flavor-chip').forEach(function(x) { x.classList.remove('on'); }); c.classList.add('on'); if (flavorData.date) { flavorData.time = null; flavorLoadTimeSlots(flavorData.date); } flavorCheckStep1(); }); // ===================== // SHARED TABLE TOGGLE // ===================== var sharedToggle = document.getElementById('flavorSharedToggle'); if (sharedToggle) { sharedToggle.addEventListener('click', function() { flavorData.shared = !flavorData.shared; sharedToggle.classList.toggle('on', flavorData.shared); }); } // ===================== // VALIDATIONS // ===================== function flavorCheckStep1() { var hasBooking = !!(flavorData.date && flavorData.time); if (flavorTotalSteps === 2) { // In 2-step mode, step 1 also contains data fields var hasData = ['flavor-first-name','flavor-last-name','flavor-email','flavor-phone'].every(function(id) { return document.getElementById(id).value.trim() !== ''; }); document.getElementById('flavorBtn1Next').disabled = !(hasBooking && hasData); } else { document.getElementById('flavorBtn1Next').disabled = !hasBooking; } } function flavorCheckStep2() { var ok = ['flavor-first-name','flavor-last-name','flavor-email','flavor-phone'].every(function(id) { return document.getElementById(id).value.trim() !== ''; }); var btn2 = document.getElementById('flavorBtn2Next'); if (btn2) btn2.disabled = !ok; } function flavorCheckStep3() { var chk = document.getElementById('flavor-accept-terms'); // El checkbox solo existe si procede; si no está, el botón queda disponible document.getElementById('flavorBtn3Confirm').disabled = chk ? !chk.checked : false; } ['flavor-first-name','flavor-last-name','flavor-email','flavor-phone'].forEach(function(id) { document.getElementById(id).addEventListener('input', function() { flavorCheckStep2(); if (flavorTotalSteps === 2) flavorCheckStep1(); }); }); (function(){ var chk = document.getElementById('flavor-accept-terms'); if (chk) chk.addEventListener('change', flavorCheckStep3); })(); function flavorValidateStep2() { var fn = document.getElementById('flavor-first-name').value.trim(); var ln = document.getElementById('flavor-last-name').value.trim(); var em = document.getElementById('flavor-email').value.trim(); var ph = document.getElementById('flavor-phone').value.trim(); if (!fn) { flavorToast(flavorI18n.nameRequired); return false; } if (!ln) { flavorToast(flavorI18n.lastNameRequired); return false; } if (!em) { flavorToast(flavorI18n.emailRequired); return false; } if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(em)) { flavorToast(flavorI18n.emailInvalid); return false; } if (!ph) { flavorToast(flavorI18n.phoneRequired); return false; } return true; } // ===================== // SUMMARY // ===================== function flavorBuildSummary() { document.getElementById('sumGuests').textContent = flavorData.guests + ' ' + (flavorData.guests === 1 ? flavorI18n.person : flavorI18n.people); if (flavorData.date) { var parts = flavorData.date.split('-'); var d = new Date(parseInt(parts[0]), parseInt(parts[1]) - 1, parseInt(parts[2])); var dn = flavorI18n.dayNames[d.getDay()].toLowerCase(); document.getElementById('sumDate').textContent = dn + ', ' + parseInt(parts[2]) + ' de ' + flavorI18n.months[parseInt(parts[1]) - 1].toLowerCase() + ' ' + parts[0]; } document.getElementById('sumTime').textContent = flavorData.time ? flavorData.time + 'h' : '\u2014'; var fn = document.getElementById('flavor-first-name').value.trim(); var ln = document.getElementById('flavor-last-name').value.trim(); document.getElementById('sumName').textContent = (fn + ' ' + ln).trim() || '\u2014'; document.getElementById('sumEmail').textContent = document.getElementById('flavor-email').value.trim() || '\u2014'; var pre = document.getElementById('flavor-prefix').value; var ph = document.getElementById('flavor-phone').value.trim(); document.getElementById('sumPhone').textContent = ph ? pre + ph : '\u2014'; document.getElementById('sumShared').textContent = flavorData.shared ? flavorI18n.yes : flavorI18n.no; document.getElementById('sumNotes').textContent = document.getElementById('flavor-notes').value.trim() || '\u2014'; var depositAmount = flavorCalculateDeposit(); var depositBox = document.getElementById('flavorDepositBox'); var cardBox = document.getElementById('flavorCardInputBox'); if (depositAmount > 0 && flavorStripeKey) { depositBox.style.display = 'block'; cardBox.style.display = 'block'; document.getElementById('flavorDepAmount').textContent = depositAmount.toFixed(2) + ' \u20AC'; var perPerson = flavorDepositPerPerson > 0 ? (flavorData.guests + ' \u00D7 ' + flavorDepositPerPerson.toFixed(2) + ' \u20AC ' + flavorI18n.perPerson) : ''; document.getElementById('flavorDepSub').textContent = perPerson; document.getElementById('flavor-submit-text').style.display = 'none'; document.getElementById('flavor-submit-text-pay').style.display = 'inline'; } else { depositBox.style.display = 'none'; cardBox.style.display = 'none'; document.getElementById('flavor-submit-text').style.display = 'inline'; document.getElementById('flavor-submit-text-pay').style.display = 'none'; } flavorGuaranteeRender(); } // ===================== // NAVIGATION BUTTONS // ===================== document.getElementById('flavorBtn1Next').addEventListener('click', function() { if (!flavorData.guests) { flavorToast(flavorI18n.selectGuests); return; } if (!flavorData.date) { flavorToast(flavorI18n.selectDate); return; } if (!flavorData.time) { flavorToast(flavorI18n.selectTime); return; } if (flavorTotalSteps === 2 && !flavorValidateStep2()) return; flavorGoStep(2); }); var btn2Back = document.getElementById('flavorBtn2Back'); if (btn2Back) btn2Back.addEventListener('click', function() { flavorGoStep(1); }); var btn2Next = document.getElementById('flavorBtn2Next'); if (btn2Next) btn2Next.addEventListener('click', function() { if (!flavorValidateStep2()) return; flavorGoStep(3); }); document.getElementById('flavorBtn3Back').addEventListener('click', function() { flavorGoStep(flavorTotalSteps === 2 ? 1 : 2); }); document.getElementById('flavorBtn3Confirm').addEventListener('click', function() { flavorSubmit(); }); // Stepper click document.querySelectorAll('.flavor-step-ind').forEach(function(el) { el.addEventListener('click', function() { var target = parseInt(el.dataset.step); if (target < flavorStep) flavorGoStep(target); }); }); // ===================== // DEPOSIT & STRIPE // ===================== function flavorCalculateDeposit() { if (!flavorRequireDeposit) return 0; return flavorDepositPerReservation + (flavorDepositPerPerson * (flavorData.guests || 0)); } function flavorGuaranteeTotal() { if (!flavorGuarantee || flavorRequireDeposit || !flavorStripeKey) return 0; var g = flavorData.guests || 0; return g >= flavorGuaranteeMin ? flavorGuaranteePP * g : 0; } function flavorMoney(v) { var s = v.toFixed(2); return (flavorGI18n.lang === 'en' ? s : s.replace('.', ',')) + ' \u20AC'; } function flavorGuaranteeRender() { var box = document.getElementById('flavorGuaranteeBox'); if (!box) return; var total = flavorGuaranteeTotal(); box.parentNode.classList.toggle('has-guarantee', total > 0); if (total <= 0) { box.style.display = 'none'; return; } var tpl = flavorGuaranteeHours > 0 ? flavorGI18n.terms : flavorGI18n.termsNoHours; document.getElementById('flavorGTerms').textContent = tpl.replace('{hours}', flavorGuaranteeHours).replace('{pp}', flavorMoney(flavorGuaranteePP)).replace('{total}', flavorMoney(total)); box.style.display = 'block'; document.getElementById('flavorCardInputBox').style.display = 'block'; } function flavorSubmitWithGuarantee() { var acc = document.getElementById('flavor-guarantee-accept'); if (acc && !acc.checked) { flavorToast(flavorGI18n.acceptRequired); return; } if (!flavorStripe || !flavorCardElement) { flavorToast(flavorGI18n.error); return; } var submitBtn = document.getElementById('flavorBtn3Confirm'); var oldHtml = submitBtn.innerHTML; submitBtn.disabled = true; submitBtn.innerHTML = '' + flavorGI18n.processing + ''; var postData = flavorGetPostData(); var customerName = (postData.first_name + ' ' + postData.last_name).trim(); var fail = function(msg) { submitBtn.disabled = false; submitBtn.innerHTML = oldHtml; var e = document.getElementById('flavor-card-errors'); if (e) e.textContent = msg || flavorGI18n.error; flavorToast(msg || flavorGI18n.error); }; fetch(flavorRestUrl + 'guarantee/setup-intent', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ shortcode_key: flavorShortcodeKey, guests: flavorData.guests, name: customerName, email: postData.email }) }) .then(function(r) { return r.json(); }) .then(function(d) { if (!d || !d.success) throw new Error((d && d.message) || flavorGI18n.error); return flavorStripe.confirmCardSetup(d.client_secret, { payment_method: { card: flavorCardElement, billing_details: { name: customerName, email: postData.email } } }); }) .then(function(res) { if (res.error) throw new Error(res.error.message); postData.guarantee_setup_intent = res.setupIntent.id; postData.guarantee_accepted = 1; document.querySelector('.flavor-loader').style.display = 'flex'; return fetch(flavorRestUrl + 'reservations', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(postData) }); }) .then(function(r) { return r.json(); }) .then(function(r) { document.querySelector('.flavor-loader').style.display = 'none'; if (!r.success) throw new Error(r.message || flavorI18n.errorCreate); submitBtn.disabled = false; submitBtn.innerHTML = oldHtml; flavorShowSuccess(r.reservation.reservation || r.reservation); }) .catch(function(err) { document.querySelector('.flavor-loader').style.display = 'none'; fail(err && err.message); }); } function flavorInitStripe() { var depositAmount = flavorCalculateDeposit(); if ((depositAmount > 0 || flavorGuaranteeTotal() > 0) && flavorStripeKey && !flavorStripe) { flavorStripe = Stripe(flavorStripeKey); var elements = flavorStripe.elements({locale: "es"}); flavorCardElement = elements.create('card', { style: { base: { fontSize: '14px', color: '#1a1a1a', fontFamily: 'Inter, -apple-system, sans-serif', '::placeholder': { color: '#c0c0c0' } }, invalid: { color: '#dc2626' } } }); flavorCardElement.mount('#flavor-card-element'); flavorCardElement.on('change', function(event) { flavorCardComplete = !!event.complete; flavorCardError = event.error ? event.error.message : ''; document.getElementById('flavor-card-errors').textContent = flavorCardError; }); } } // ===================== // SUBMIT // ===================== function flavorSubmit() { var _chk = document.getElementById('flavor-accept-terms'); if (_chk && !_chk.checked) { flavorToast(flavorI18n.acceptTerms); return; } // In 2-step mode, validate step2 fields before submit if (flavorTotalSteps === 2 && !flavorValidateStep2()) return; if (flavorGuaranteeTotal() > 0) { flavorSubmitWithGuarantee(); return; } var depositAmount = flavorCalculateDeposit(); if (depositAmount > 0 && flavorStripeKey && flavorCardElement) { flavorSubmitWithPayment(); } else { flavorSubmitWithoutPayment(); } } function flavorGetPostData() { var prefix = document.getElementById('flavor-prefix').value; var phone = document.getElementById('flavor-phone').value.trim(); return { restaurant_id: flavorRestaurantId, shortcode_key: flavorShortcodeKey, guests: flavorData.guests, reservation_date: flavorData.date, reservation_time: flavorData.time, first_name: document.getElementById('flavor-first-name').value, last_name: document.getElementById('flavor-last-name').value, email: document.getElementById('flavor-email').value, phone: prefix + phone, allergies: document.getElementById('flavor-allergies').value, dietary_restrictions: '', notes: document.getElementById('flavor-notes').value, shared_table: flavorData.shared ? 1 : 0, // Idioma del formulario: decide el idioma de los emails de la reserva y del cliente lang: "es" }; } function flavorSubmitWithoutPayment() { document.querySelector('.flavor-loader').style.display = 'flex'; fetch(flavorRestUrl + 'reservations', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(flavorGetPostData()) }) .then(function(r) { return r.json(); }) .then(function(r) { document.querySelector('.flavor-loader').style.display = 'none'; if (r.success) { flavorShowSuccess(r.reservation.reservation || r.reservation); } else { flavorShowError(r.message || flavorI18n.errorCreate); } }) .catch(function() { document.querySelector('.flavor-loader').style.display = 'none'; flavorShowError(flavorI18n.error); }); } // Tarjeta completa (lo dice Stripe Elements) y cobro pendiente reutilizable: cada intento fallido // (número incompleto, tarjeta rechazada…) ya no crea un pago nuevo «Incompleto» en Stripe. var flavorCardComplete = false, flavorCardError = '', flavorPendingIntent = null; function flavorSubmitWithPayment() { if (!flavorCardComplete) { var msg = flavorCardError || "Completa los datos de la tarjeta"; document.getElementById('flavor-card-errors').textContent = msg; flavorToast(msg); return; } var submitBtn = document.getElementById('flavorBtn3Confirm'); submitBtn.disabled = true; submitBtn.innerHTML = '' + flavorI18n.paymentProcessing + ''; var postData = flavorGetPostData(); var customerName = postData.first_name + ' ' + postData.last_name; var customerEmail = postData.email; var intentSig = [flavorRestaurantId, flavorData.guests, customerEmail].join('|'); var intentReq = (flavorPendingIntent && flavorPendingIntent.sig === intentSig) ? Promise.resolve({ success: true, data: { client_secret: flavorPendingIntent.secret } }) : fetch(flavorRestUrl + 'payment/create-intent', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ restaurant_id: flavorRestaurantId, guests: flavorData.guests, name: customerName, email: customerEmail }) }).then(function(resp) { return resp.json(); }); intentReq .then(function(paymentData) { if (!paymentData.success) throw new Error(paymentData.message || flavorI18n.errorPayment); flavorPendingIntent = { sig: intentSig, secret: paymentData.data.client_secret }; return flavorStripe.confirmCardPayment(paymentData.data.client_secret, { payment_method: { card: flavorCardElement, billing_details: { name: customerName, email: customerEmail } } }).then(function(result) { if (result.error) { // Ya cobrado (p. ej. doble clic): se sigue con la reserva con ese mismo pago if (result.error.payment_intent && result.error.payment_intent.status === 'succeeded') return result.error.payment_intent.id; throw new Error(result.error.message); } flavorPendingIntent = null; return result.paymentIntent.id; }); }) .then(function(paymentIntentId) { postData.payment_intent_id = paymentIntentId; postData.deposit_paid = 1; return fetch(flavorRestUrl + 'reservations', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(postData) }); }) .then(function(response) { return response.json(); }) .then(function(r) { if (!r.success) throw new Error(r.message || flavorI18n.errorCreate); submitBtn.disabled = false; flavorShowSuccess(r.reservation.reservation || r.reservation); }) .catch(function(error) { submitBtn.disabled = false; submitBtn.innerHTML = '' + flavorI18n.paymentProcessing + ''; document.getElementById('flavor-card-errors').textContent = error.message; flavorToast(error.message); }); } // ===================== // SUCCESS / ERROR // ===================== // Ejecuta un snippet de tracking pegado por el restaurante desde el backoffice. // El snippet se sirve como' + esc(R.name || '') + '' + (R.address ? '
' + esc(R.address) : '') +
(R.maps ? ' · ' + flavorI18n.okDirections + '' : '') + '
' + (flavorI18n.okMail || '').replace('%s', '' + esc(postData.email) + '') + '
' + '' + message + '
' + '' + 'Descubre las cuevas de Porto Cristo: formación geológica, el lago Martel, horarios, precios y consejos…
Todo sobre Cala Bona: playa, servicios, accesibilidad, precios, cómo llegar, buceo y qué ver en…
Descubre la Pollença marinera: pesca de bajura, platos con historia, restaurantes del muelle y el…
Cómo llegar al Torrent de Pareis desde Palma: rutas en coche, barco y transporte público,…
Descubre las diferencias entre aceite de oliva virgen extra, virgen y refinado: clasificación oficial UE,…
Aprende a realizar una cata de aceite de oliva virgen extra paso a paso: fases…