// =========================================================================
// 🔄 МОДУЛЬ АВТОНОМНОГО МЕНЮ, ИЗОЛИРОВАННОГО КАЛЕНДАРЯ И ДИСКА v25.6 (SaaS)
// =========================================================================

// Константа управления — ID твоей главной управляющей таблицы сотрудников
var MASTER_CONTROL_ID = '15lc3jj5D4eadrrx0amG-rOE0yCPo2D1P51Hu-T-aV0c';

// 1. Автоматическое создание меню в Excel-таблице любого клиента Balloon CRM
function onOpen() {
 try {
  var ui = SpreadsheetApp.getUi();
  ui.createMenu('🛠 CRM Платформа')
   .addItem('📱 Открыть Калькулятор', 'showSidebar')
   .addSeparator()
   .addItem('📥 Обновить связку Tilda (YML)', 'updateTildaExport')
   .addSeparator()
   .addItem('📂 1. Настроить личный Диск для photo', 'setupClientFolder')
   .addItem('📅 2. Связать личный Календарь', 'setupClientCalendar')
   .addToUi();
 } catch(e) {}
}

// 2. Функция вызова боковой панели калькулятора внутри Excel
function showSidebar() {
 var html = HtmlService.createHtmlOutputFromFile('Sidebar').setTitle('Калькулятор').setWidth(350);
 SpreadsheetApp.getUi().showSidebar(html);
}

// 3. Умная настройка и принудительное авто-открытие папки на Гугл Диске в браузере
function setupClientFolder() {
 var ss = SpreadsheetApp.getActiveSpreadsheet();
 var nSheet = ss.getSheetByName('Настройки') || ss.insertSheet('Настройки');
 try {
  var compName = nSheet.getLastRow() > 0 ? nSheet.getRange(2, 4).getValue().toString().trim() : "Студия";
  var folder = DriveApp.createFolder("📸 Фото заказов — " + (compName || "Balloon"));

  // Делаем её полностью доступной по ссылке для загрузки и просмотра
  folder.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);

  // Записываем ID папки строго в настройки F2 для ядра doPost
  nSheet.getRange(2, 6).setValue(folder.getId());
  SpreadsheetApp.flush();

  // СВЕРХУДОБНЫЙ ХАК: Принудительно открываем созданную папку на экране менеджера!
  var folderUrl = folder.getUrl();
  var htmlOutput = HtmlService.createHtmlOutput(
   '<script>window.open("' + folderUrl + '", "_blank"); google.script.host.close();</script>'
  ).setWidth(10).setHeight(10);
  SpreadsheetApp.getUi().showModalDialog(htmlOutput, "Открытие папки...");

 } catch(e) {
  SpreadsheetApp.getUi().alert("❌ Ошибка настройки Диска", e.toString(), SpreadsheetApp.getUi().ButtonSet.OK);
 }
}
// 4. Автоматическое создание отдельного календаря для заказов (без смешивания с личным!)
function setupClientCalendar() {
 var ss = SpreadsheetApp.getActiveSpreadsheet();
 var nSheet = ss.getSheetByName('Настройки') || ss.insertSheet('Настройки');
 try {
  var calendarName = "🎈 CRM Balloon — ЗАКАЗЫ";
  var targetCalendar = null;

  // Ищем, может быть у пользователя уже создан такой календарь, чтобы не плодить дубликаты
  var calendars = CalendarApp.getCalendarsByName(calendarName);
  if (calendars.length > 0) {
   targetCalendar = calendars[0];
  } else {
   // Создаем абсолютно НОВЫЙ, отдельный календарь для доставок шаров
   targetCalendar = CalendarApp.createCalendar(calendarName, {
    summary: "Сюда автоматически выгружаются все доставки и монтажи шаров из CRM Balloon. Вы можете раздать доступ к этому календарю своей команде.",
    timeZone: "GMT+10"
   });
  }

  // Записываем ID нового календаря в настройки E2 для ядра doPost
  nSheet.getRange(2, 5).setValue(targetCalendar.getId());
  SpreadsheetApp.flush();

  SpreadsheetApp.getUi().alert(
   "✅ УСПЕШНО СВЯЗАНО!",
   "Создан отдельный изолированный календарь: \"" + calendarName + "\".\n\nID записан в ячейку настроек. Личные дела владельца в полной безопасности! Теперь вы можете раздать доступ к нему своим сотрудникам и водителям.",
   SpreadsheetApp.getUi().ButtonSet.OK
  );

 } catch(e) {
  SpreadsheetApp.getUi().alert("❌ Ошибка создания Календаря", e.toString(), SpreadsheetApp.getUi().ButtonSet.OK);
 }
}
// =========================================================================
// 🔄 SaaS-ИМПОРТЕР ТОВАРОВ TILDA YML: UID, TITLE, URL v30.0 (ЯДРО)
// =========================================================================
function coreUpdateTildaExport(sheetId) {

 if (!sheetId) return "error: no sheet id";

 try {
  var ss = SpreadsheetApp.openById(sheetId);
  var goodsSheet = ss.getSheetByName('Товары') || ss.getSheetByName('каталог') || ss.getSheetByName('Каталог');
  var settingsSheet = ss.getSheetByName('Настройки') || ss.getSheetByName('настройки');

  if (!goodsSheet || !settingsSheet) return "error: sheets not found";

  // Считываем индивидуальную YML-ссылку пользователя из ячейки B2 листа Настройки
  var ymlUrl = settingsSheet.getRange("B2").getValue().toString().trim();
  if (!ymlUrl || ymlUrl.indexOf("http") === -1) return "error: invalid yml url in B2";

  var response = UrlFetchApp.fetch(ymlUrl);
  var xmlText = response.getContentText();
  var document = XmlService.parse(xmlText);
  var shop = document.getRootElement().getChild('shop');
  var offers = shop.getChild('offers').getChildren('offer');

  // Собираем карту актуальных товаров из YML Tilda (Ключ — Tilda UID)
  var tildaOffersMap = {};
  offers.forEach(function(offer) {
   var uid = String(offer.getAttribute('id') || '').trim(); // Tilda UID
   var title = offer.getChildText('name') || offer.getChildText('model') || ""; // Title
   var url = offer.getChildText('url') || ""; // Url

   title = String(title).trim();
   url = String(url).trim();

   if (uid) {
    tildaOffersMap[uid] = { uid: uid, title: title, url: url };
   }
  });

  // Сканируем текущие строки листа "Товары" (колонки A, B, C) для умного слияния
  var lastRow = goodsSheet.getLastRow();
  if (lastRow < 1) lastRow = 1;
  var range = goodsSheet.getRange(1, 1, lastRow, 3); // Читаем А (UID), B (Title), C (Url)
  var currentValues = range.getValues();

  var existingIdsLog = {};

  for (var i = 1; i < currentValues.length; i++) {
   var rowUid = String(currentValues[i] || '').trim();
   if (!rowUid) continue;

   existingIdsLog[rowUid] = true;

   // УМНОЕ УДАЛЕНИЕ: Если UID товара нет в новом YML, очищаем строго колонки А, B, C этой строки
   if (!tildaOffersMap[rowUid]) {
    goodsSheet.getRange(i + 1, 1, 1, 3).setValues([["", "", ""]]);
    goodsSheet.getRange(i + 1, 1).setNote("Товар удален из каталога Tilda: UID " + rowUid);
   } else {
    // Если товар остался, обновляем его Title (B) и Url (C) актуальными данными
    var activeOffer = tildaOffersMap[rowUid];
    goodsSheet.getRange(i + 1, 2, 1, 2).setValues([[activeOffer.title, activeOffer.url]]);
   }
  }

  // УМНОЕ ДОБАВЛЕНИЕ: Дописываем новинки в самый низ листа
  for (var keyUid in tildaOffersMap) {
   if (!existingIdsLog[keyUid]) {
    var nextEmptyRow = goodsSheet.getLastRow() + 1;
    var newOffer = tildaOffersMap[keyUid];
    goodsSheet.getRange(nextEmptyRow, 1, 1, 3).setValues([[newOffer.uid, newOffer.title, newOffer.url]]);
   }
  }

  SpreadsheetApp.flush();
  return "success";
 } catch(eYml) {
  return "error: " + eYml.toString();
 }
}

Made on
Tilda