Надо перенести данные из одного столбца в другой, но логика алгоритма не работает

Не могу найти ошибку, тк в Apps Script журнал выполнения(логи) у меня не подгружается. Я пишу алгоритм для склада. Мне нужно, чтобы при добавлении данных в столбик D в соседней ячейке(столбце E) появлялась дата создания этой информации. Я смог реализовать алгоритм вот так

function onEdit(e) {
  if (!e || !e.range || !e.source || e.range.getSheet().getName() !== "все приходы") return;
  
  var range = e.range;
  var ss = e.source;
  var sheet = range.getSheet();
  var row = range.getRow(); 
  var col = range.getColumn();

  if (col === 4 && sheet.getRange(row, 5).isBlank()) { 
    sheet.getRange(row, 5).setValue(new Date());
  }
}

Однако, мне также потребовалось добавить новую функцию. В столбце N хранится информация, которая через 20 дней устаревает и ее нужно записать в столбец M, дабы не возникало проблем на других листах где ведется учёт, на который влияет столбец N. Следовательно алгоритм должен быть таким: Сверяем сегодняшнюю дату и дату создания записанную в столбце E у последних 40 строк(чтобы не проверять каждый раз всю страницу); если старше 20 дней => копируем данные N вставляем в M и удаляем из N. Вот реализация с комментариями, постарался максимально подробно всё описать(алерты использую тк логи не работают, однако они не выводятся).

function onEdit(e) {
  if (!e || !e.range || !e.source) return;
  const sheet = e.range.getSheet();
  const ui = SpreadsheetApp.getUi();
  
  // Проверяем нужный лист
  if (sheet.getName() !== "все приходы") return;
  
  const range = e.range;
  const row = range.getRow();
  const col = range.getColumn();
  const lastRow = sheet.getLastRow();
  const startRow = Math.max(lastRow - 39, 1);
  
  // Флаг для отслеживания добавления новой даты
  let dateWasAdded = false;

  // 1. Вставка даты в столбец E при изменении D (только если E пусто)
  if (col === 4 && sheet.getRange(row, 5).isBlank()) {
    try {
      sheet.getRange(row, 5).setValue(new Date());
      ui.alert("Дата добавлена", `В строке ${row} добавлена текущая дата`, ui.ButtonSet.OK);
      dateWasAdded = true;
    } catch (error) {
      ui.alert("Ошибка", `Не удалось добавить дату в строке ${row}:\n${error.message}`, ui.ButtonSet.OK);
      return;
    }
  }

  // 2. Проверка даты и перемещение данных (для последних 40 строк)
  if (col === 4 && row >= startRow) {
    try {
      const dateCell = range.offset(0, 1);
      const dateValue = dateCell.getValue();
      
      // Проверка что значение является датой
      if (!dateValue) {
        ui.alert("Ошибка", `Ячейка E${row} пустая!`, ui.ButtonSet.OK);
        return;
      }
      
      let jsDate;
      // Если мы только что добавили дату - используем её как объект Date
      if (dateWasAdded) {
        jsDate = new Date(dateValue);
      } 
      // Если дата уже была - конвертируем из Excel формата
      else if (typeof dateValue === 'number') {
        jsDate = new Date(Math.round((dateValue - 25569) * 86400 * 1000));
      } 
      // Если это строка - пытаемся распарсить
      else if (typeof dateValue === 'string') {
        jsDate = new Date(dateValue);
        if (isNaN(jsDate.getTime())) {
          ui.alert("Ошибка", `Неверный формат даты в E${row}: "${dateValue}"`, ui.ButtonSet.OK);
          return;
        }
      }
      // Если это объект Date - используем как есть
      else if (dateValue instanceof Date) {
        jsDate = new Date(dateValue);
      }
      // Неизвестный формат
      else {
        ui.alert("Ошибка", `Неизвестный формат даты в E${row}: ${typeof dateValue}`, ui.ButtonSet.OK);
        return;
      }
      
      // Корректировка времени для сравнения
      jsDate.setHours(0, 0, 0, 0);
      const today = new Date();
      today.setHours(0, 0, 0, 0);
      
      // Вычисление разницы в днях
      const diffDays = Math.floor((today - jsDate) / (1000 * 60 * 60 * 24));
      
      // Перемещение данных при разнице >=20 дней
      if (diffDays >= 20) {
        const sourceColN = range.offset(0, 10);
        const targetColM = range.offset(0, 9);
        const dataToMove = sourceColN.getValue();
        
        if (!dataToMove) {
          ui.alert("Внимание", `В столбце N${row} нет данных для перемещения`, ui.ButtonSet.OK);
          return;
        }
        
        // Выполняем перемещение
        targetColM.setValue(dataToMove);
        sourceColN.clearContent();
        
        // Показываем успешное сообщение
        ui.alert(
          "Данные перемещены", 
          `В строке ${row} данные перемещены из N в M\n` +
          `Дата: ${jsDate.toLocaleDateString()}\n` +
          `Разница: ${diffDays} дней`,
          ui.ButtonSet.OK
        );
      }
    } catch (error) {
      ui.alert("Критическая ошибка", `Ошибка в строке ${row}:\n${error.message}`, ui.ButtonSet.OK);
    }
  }
}

Собственно вопрос - где закралась ошибка? Алгоритм реализует только часть с добавлением даты, но перемещение из M в N не происходит. Может логика Apps Script не позволяет onEdit использовать таким образом? или всё проще?


Ответы (1 шт):

Автор решения: Kamupo

Надеюсь триггер настроен правильно. Некоторые действия излишни, пробуй:

function onEdit(e) {
  if (!e || !e.range || !e.source) return;
  const sheet = e.range.getSheet();
  const ui = SpreadsheetApp.getUi();

  // Проверяем нужный лист
  if (sheet.getName() !== "все приходы") return;

  const range = e.range;
  const row = range.getRow();
  const col = range.getColumn();
  const lastRow = sheet.getLastRow();
  const startRow = Math.max(lastRow - 39, 1);

  // Проверка, что изменён столбец D
  if (col !== 4) return;

  // Флаг для отслеживания добавления новой даты
  let dateWasAdded = false;

  // 1. Вставка даты в столбец E при изменении D (только если E пусто)
  const dateCell = sheet.getRange(row, 5);
  const dateValue = dateCell.getValue();

  if (dateValue === null || dateValue === "") {
    try {
      dateCell.setValue(new Date());
      dateWasAdded = true;
      // ui.alert("Дата добавлена", `В строке ${row} добавлена текущая дата`, ui.ButtonSet.OK);
    } catch (error) {
      ui.alert("Ошибка", `Не удалось добавить дату в строке ${row}:\n${error.message}`, ui.ButtonSet.OK);
      return;
    }
  }

  // 2. Проверка даты и перемещение данных (для последних 40 строк)
  if (row >= startRow) {
    try {
      let jsDate;

      if (dateWasAdded) {
        jsDate = new Date(dateCell.getValue());
      } else if (typeof dateValue === 'number') {
        jsDate = new Date((dateValue - 25569) * 86400 * 1000);
      } else if (typeof dateValue === 'string') {
        jsDate = new Date(dateValue);
        if (isNaN(jsDate.getTime())) {
          ui.alert("Ошибка", `Неверный формат даты в E${row}: "${dateValue}"`, ui.ButtonSet.OK);
          return;
        }
      } else if (dateValue instanceof Date) {
        jsDate = new Date(dateValue);
      } else {
        ui.alert("Ошибка", `Неизвестный формат даты в E${row}: ${typeof dateValue}`, ui.ButtonSet.OK);
        return;
      }

      // Корректировка времени для сравнения
      jsDate.setHours(0, 0, 0, 0);
      const today = new Date();
      today.setHours(0, 0, 0, 0);

      // Вычисление разницы в днях
      const diffDays = Math.floor((today - jsDate) / (1000 * 60 * 60 * 24));

      // Перемещение данных при разнице >=20 дней
      if (diffDays >= 20) {
        const sourceColN = sheet.getRange(row, 14); // N
        const targetColM = sheet.getRange(row, 13); // M
        const dataToMove = sourceColN.getValue();

        if (!dataToMove) {
          ui.alert("Внимание", `В столбце N${row} нет данных для перемещения`, ui.ButtonSet.OK);
          return;
        }

        // Выполняем перемещение
        targetColM.setValue(dataToMove);
        sourceColN.clearContent();

        // Показываем успешное сообщение
        ui.alert(
          "Данные перемещены",
          `В строке ${row} данные перемещены из N в M\n` +
          `Дата: ${jsDate.toLocaleDateString()}\n` +
          `Разница: ${diffDays} дней`,
          ui.ButtonSet.OK
        );
      }
    } catch (error) {
      ui.alert("Критическая ошибка", `Ошибка в строке ${row}:\n${error.message}`, ui.ButtonSet.OK);
    }
  }
}

→ Ссылка