Руководство пользователя nERP

Здесь — ответы на типовые вопросы без внутреннего жаргона: карта интерфейса, сохранение, диагностика и сводка. Справочник функций — на других вкладках.

Быстрый старт: что вы видите на экране

Что это — карта интерфейса и базовые понятия.

  • Проект / workspace — ваш рабочий контейнер: листы, настройки, участники.
  • Кошелёк (wallet) — идентификатор аккаунта в экосистеме; по нему проще понять, в каком контексте вы сейчас (особенно при доступе к чужим данным).
  • Лист — таблица, доска или сводка (дашборд). Тип задаёт, как вводятся данные и какие формулы уместны.
  • Столбец (поле) — колонка с типом: текст, число, дата, список, файл и т.д. Справа при редактировании колонки часто появляются дополнительные поля — это настройки типа, их нужно заполнять осмысленно (см. вкладку «Типы полей» и раздел ниже про маски и списки).

Подробнее про типы листов и формулы — вкладки «Типы листов», «Формулы…». Для разработчиков модулей — «Интеграция модулей».

Сохранение и автосохранение

Что это — когда изменения попадают в проект.

  • Верхняя кнопка «Сохранить» (на таблице/листе) отправляет накопленные изменения в проект. Без сохранения часть правок может остаться только локально в браузере.
  • Автосохранение (если включено в настройках) периодически нажимает сохранение за вас — уточните лимиты в своей версии (интервал / объём).

Когда обязательно нажать «Сохранить» вручную

  • после правок столбцов, категорий доски, блоков сводки;
  • после настройки шаблонов и связок полей (Word/PDF);
  • если автосохранение выключено — после любых значимых правок.

UX: рядом с «Сохранить» полезен индикатор «есть несохранённые изменения» и короткая подсказка.

Ошибки, диагностика и баг-репорт

Когда использовать — что-то не сохраняется, «пустые» списки, конфликт категорий, схема не импортируется.

Как настроить по шагам

  1. Скачайте / сформируйте диагностический пакет из интерфейса nERP (как предусмотрено в вашей сборке).
  2. Сделайте скриншоты экрана до и после ошибки.
  3. Опишите: лист, кошелёк, роль (владелец / гость), шаги «нажала А, затем Б».
  4. Укажите браузер и время. Не отправляйте приватные ключи и пароли.

Это сильно ускоряет разбор сценариев вроде «не выбрался один пункт доступа», «конфликт категорий полей», «публикация схемы».

Сводка (дашборд): размер, порядок, разделитель

Что это — лист из блоков: показатели, таблица, разделитель, перенос строки.

Размер блока — сетка из 12 колонок. Числа в UI можно читать так:

Значение sizeЧеловечески
12Вся ширина строки
6Половина (два блока в ряд)
4Треть (три блока в ряд)
3Четверть (четыре блока в ряд)

Порядок (order) — число сортировки: меньшее значение обычно выше / левее в потоке блоков (уточняйте по своей версии, если порядок кажется обратным — приложите диагностику).

Редактирование блока — клик по области блока открывает настройки; если неочевидно, наведите на блок и ищите зону клика или меню действий в вашей сборке.

Разделитель / перенос строки — служебные блоки; удаление через настройки блока (если в UI нет явной кнопки удаления — это повод для UX-задачи).

Формулы в сводке другие, чем в ячейке таблицы: с явным указанием листа и столбца, см. вкладку «Формулы сводки».

UX: кнопка «Редактировать» при наведении, человекочитаемые подписи размеров, удаление разделителя одной кнопкой.

Инструкция по формулам

Все формулы начинаются со знака =. Работают базовые операции + - * /, степень ^, постфикс % (как в Excel: деление на 100), склейка текста & и скобки для приоритета, например =(1+2)*3 или ="Итого: "&СУММ(А;Б).

Синтаксис и общие правила

  • Вводите формулу со знака = — например: =1+2.
  • Имена встроенных функций в русской локали — кириллицей: =СУММА(...), =ЕСЛИ(...) и т.д.
  • Аргументы функций разделяются точкой с запятой ; (не запятая).
  • Операторы ^ (степень), % после числа и & (текст) описаны в справочнике функций и в formulaExpressionEval.js.
  • Имена столбцов в формулах — как подписи колонок в таблице; при необходимости оборачивайте в фигурные скобки: {Название колонки}, если имя содержит пробелы или совпадает с зарезервированными словами (см. подсказки в UI редактора).

Даты, возраст и комбинирование функций

Функции СЕГОДНЯ, СЕЙЧАС, ДАТА, ЗНАЧЕНИЕ, ГОД, МЕСЯЦ, ДЕНЬ, РАЗНДАТ, AGE и их английские аналоги работают по отдельности и в выражениях (аргументы через ;). Это не полный Excel: поддерживается только то, что перечислено на вкладке «Формулы для столбов» и в nerp/js/formulas/formulaExpressionEval.js.

Пример полных лет по дате рождения (классическая связка):

=ГОД(СЕГОДНЯ()-ДАТА(ЗНАЧЕНИЕ(Дата рождения)))

Эквивалент короче: =AGE(Дата рождения) или =РАЗНДАТ(ДАТА(Дата рождения);СЕГОДНЯ();"Y").

  • СЕГОДНЯ() — сегодня (полночь, локальный календарь).
  • ДАТА — один аргумент (текст/столбец с датой) или три: год;месяц;день.
  • ГОД — от даты даёт календарный год; от разности двух дат (дата1 - дата2) — полных лет между ними.
  • ЗНАЧЕНИЕ — явно взять значение ячейки для парсинга в ДАТА и др.

Даты в ячейках: ДД.ММ.ГГГГ, ISO ГГГГ-ММ-ДД и др. см. парсер в formulaExpressionEval.js.

Где какие формулы

  • Формулы для столбов — обычные ячейки строк; здесь же агрегаты по связанным листам (СУММАИЗ, СРЗНАЧИЗ, СУММАЕСЛИ и др.).
  • Формулы для итого — строка итогов таблицы; часто это =СУММА, =СРЗНАЧ, =СУММАЕСЛИ(Столбец>0) и форматирование =ДЕНЬГИ(...).
  • Формулы сводки — виджеты дашборда; в аргументах обычно явно указываются лист и столбец, например =СУММА(Продажи;Сумма).

Документация для AI и расширенные сценарии nERP

Контекстную документацию по сущностям nERP, типам колонок, отчётам, фильтрам и high-level действиям ассистента поддерживает сервис novij-ai-service (каталог kb/nerp в том репозитории). Пользовательское руководство — на вкладке «Руководство пользователя». Этот сайт nerp-docs также содержит справочник функций в ячейках и раздел для разработчиков модулей.

Формулы для столбцов

Список подгружается из formulas-docs.json. Слева — оглавление по функциям.

Формулы для итого

Строка итогов таблицы — см. оглавление слева.

Формулы сводки (дашборд)

Виджеты и блоки сводки — см. оглавление слева.

Типы листов и формулы

Тип листа задаёт, где считаются формулы: по строке, по карточке или агрегатами по всему листу.

Таблица (table)

Обычная таблица: формулы в столбцах вычисляются для каждой строки. Есть строка итогов с отдельным набором формул (вкладка «Формулы для итого»).

Примеры построчных формул (имена столбцов — как у вас на листе):

=Цена*Количество

В справочнике: СУММ, ОКРУГЛИТЬ.

=AGE(Дата рождения)

В справочнике: AGE, ДАТА, ГОД.

Строка итогов — другой синтаксис, см. СУММА (итого), СРЗНАЧ (итого).

Доска (board)

Это тот же построчный расчёт, что и в таблице: у каждой карточки есть строка данных, в столбцах задаёте формулы по этой строке. Отличия: нет строки итогов; карточки сгруппированы по колонкам доски (категориям); подпись на карточке обычно берётся из столбца defaultColumn в модели листа.

Раньше здесь стояла выдуманная конструкция вроде =СТАТУС&" — "&СУММА без пояснения имён столбцов — так действительно выглядело как «бред»: в формуле должны быть реальные подписи ваших колонок, как в таблице.

Примеры формул на доске (подставьте свои имена полей):

=Цена*Количество

То же, что в таблице: перемножаются два числовых столбца текущей карточки.

=СЦЕПИТЬ(Название;" · ";Статус)

Склейка текста для подписи или отдельного столбца — см. СЦЕПИТЬ, ЕПУСТО.

Как пользоваться доской

  1. Настройте колонки (в т.ч. поле статуса/категории, если оно отдельное).
  2. Задайте категории колонок доски и категорию по умолчанию в настройках листа.
  3. Новая карточка появится в колонке по умолчанию — перетащите её в нужную колонку.
  4. После изменения колонок или категорий нажмите Сохранить.

Сводка (dashboard)

Блоки indicators, table, separator, lineBreak. Здесь другой набор формул — агрегаты по листу, с явным указанием листа и столбца. Построчные функции вроде ГОД, СЕГОДНЯ, AGE для ячейки строки не применяются в этих блоках.

Размер в сетке 12 колонок — см. таблицу на вкладке «Руководство пользователя» (раздел «Сводка»): 3 ≈ четверть ширины, 4 ≈ треть, 6 ≈ половина, 12 — вся строка.

Порядок блоков — поле order; меньшее число обычно отображается раньше (уточняйте по версии при сомнениях).

Примеры формул сводки (переход к карточке в справочнике):

=СУММА(Продажи;Сумма)

СУММА (сводка)

=СУММАЕСЛИ(Заказы;Сумма;Статус;Оплачен)

СУММАЕСЛИ (сводка)

=УНИКАЛЬНЫЕ(Клиенты;Город)

УНИКАЛЬНЫЕ

Типы полей и формулы

Тип поля отвечает на простой вопрос: что человек будет вводить в эту колонку — текст, число, дату, файл, один вариант из списка или несколько вариантов. В настройках колонки сначала выбирают тип, потом заполняют дополнительные поля, если они нужны. Формулы — необязательная часть: они нужны только когда значение должно считаться автоматически.

Однострочный текст (input)

Когда выбирать. Для короткого текста: имя клиента, номер договора, артикул, телефон, короткий статус.

Что настроить. Введите название колонки, например «Клиент» или «Номер договора». Больше ничего обязательного обычно не нужно.

Что вводит пользователь. Пишет текст прямо в ячейку.

Иванов И.И.
Договор №42
+375291234567

Что будет. Текст сохранится как есть. Если колонка узкая, на экране он может выглядеть обрезанным, но значение не пропадает.

Если нужна формула. Например, собрать ФИО из двух колонок:

=СЦЕПИТЬ(Фамилия;" ";Имя)

Подробнее: СЦЕПИТЬ, ДЛСТР, СЖПРОБЕЛЫ.

Многострочный текст (textarea)

Когда выбирать. Для длинного комментария, описания задачи, заметок по клиенту.

Что настроить. Дайте колонке понятное имя: «Комментарий», «Описание», «Что сделать».

Что вводит пользователь. Пишет несколько строк текста.

Клиент просит перезвонить завтра.
Уточнить адрес доставки.
Причина отказа: дорого.

Что будет. Текст сохранится вместе с переносами строк. Это удобно читать в карточке строки, но в таблице длинный текст может занимать много места.

Если нужна формула. Можно проверить, пустой ли комментарий, или посчитать длину текста:

=ЕСЛИ(ЕПУСТО(Комментарий);"Нет комментария";"Есть комментарий")

Подробнее: ЕСЛИ, ЕПУСТО, ДЛСТР.

Редактируемый текст (editable)

Когда выбирать. Когда текст нужно красиво оформить: сделать заголовок, жирный текст, список, ссылку.

Что настроить. Назовите колонку, например «Инструкция», «Техническое задание», «Описание для клиента».

Что вводит пользователь. Пишет текст в редакторе и применяет оформление.

Заголовок
- первый пункт
- второй пункт
Важно: согласовать макет до пятницы.

Что будет. Пользователь увидит оформленный текст. Если потом использовать это поле в формулах, помните: там может быть не просто текст, а текст с оформлением.

Если нужна формула. Для простых проверок лучше использовать отдельную обычную текстовую колонку. Для длины текста можно смотреть ДЛСТР.

Число (number)

Когда выбирать. Для суммы, количества, цены, процента, веса, часов.

Что настроить. Название колонки: «Цена», «Количество», «Скидка». Если колонка должна считаться сама, добавьте формулу.

Что вводит пользователь. Только число.

120
12,5
-3

Что будет. Числа можно складывать, умножать и сравнивать. Если вместо числа написать слово, система может не принять значение или формула получит ошибку.

Примеры формул. Посчитать сумму строки:

=Цена*Количество

Округлить результат:

=ОКРУГЛИТЬ(Цена*Количество;2)

Подробнее: ОКРУГЛИТЬ, MIN, MAX.

=ЕСЛИ(Скидка>0;Сумма*(1-Скидка);Сумма)

Подробнее: ЕСЛИ, ЕСЛИОШИБКА. Для строки итогов используйте отдельную формулу СУММА.

Диапазон (slider)

Когда выбирать. Когда человеку проще выбрать значение ползунком: процент готовности, оценка от 1 до 10, приоритет.

Что настроить. В настройках укажите нижнюю и верхнюю границу. Например: от 0 до 100.

Что вводит пользователь. Двигает ползунок, а в ячейке получается число.

0
50
100

Что будет. Пользователь не сможет случайно выбрать число вне заданного диапазона. Если границы настроены неверно, поле будет вести себя непредсказуемо.

Если нужна формула. С ползунком работают те же формулы, что с числом:

=ЕСЛИ(Готовность=100;"Готово";"В работе")

Подробнее: ЕСЛИ, ОКРУГЛИТЬ.

Дата (date)

Когда выбирать. Для дня рождения, срока оплаты, даты звонка, даты начала и окончания задачи.

Что настроить. Название колонки: «Дата оплаты», «Дата рождения», «Срок». Обычно больше ничего не нужно.

Что вводит пользователь. Выбирает дату в календаре или вводит её вручную.

15.03.1990
2026-01-10
06.05.2026

Что будет. С датой можно считать возраст, срок между двумя датами, месяц, год. Если написать несуществующую дату, система может не сохранить значение.

Примеры формул. Посчитать возраст:

=AGE(Дата рождения)

Посчитать количество дней между датами:

=РАЗНДАТ(ДАТА(Начало);ДАТА(Конец);"D")

Подробнее: AGE, ДАТА, РАЗНДАТ, СЕГОДНЯ.

Флаг (checkbox)

Когда выбирать. Для ответа «да / нет»: оплачено, активно, архив, согласовано, отправлено.

Что настроить. Название колонки, например «Оплачен» или «Согласовано».

Что делает пользователь. Ставит или снимает галочку.

галочка стоит → да
галочки нет → нет

Что будет. В формулах это удобно использовать как условие: если галочка стоит — сделать одно, если нет — другое.

Примеры формул:

=ЕСЛИ(Оплачен;Сумма;0)
=ЕСЛИ(И(Активен;Не архив);1;0)

Подробнее: ЕСЛИ, И, ИЛИ, НЕ.

Список (select)

Когда выбирать. Когда в колонке должен быть только один вариант из заранее заданного списка: статус, тип клиента, город, категория.

Что настроить. В настройках колонки добавьте варианты. Например: «Новый», «В работе», «Готово».

Что делает пользователь. Открывает список и выбирает один пункт.

Новый
В работе
Готово

Что будет. В ячейку попадёт выбранный текст. Если вариантов не настроить, пользователю нечего будет выбрать.

Примеры формул. Если статус «Готово», показать 100:

=ЕСЛИ(Статус="Готово";100;0)

Если нужно подтянуть значение из другого листа, см. ССЫЛКА. Для условий — ЕСЛИ.

Мультисписок (multiselect)

Когда выбирать. Когда в одной строке нужно отметить сразу несколько вариантов. Например, у задачи может быть несколько тегов, у клиента — несколько интересов, у заявки — несколько каналов связи.

Что настроить. В настройках колонки заранее добавьте варианты. Например: «Срочно», «Документы», «Доставка», «Оплата».

Что делает пользователь. Открывает список и отмечает один или несколько пунктов.

Срочно, Документы
Встреча, Звонок
Москва, Минск

Что будет. В ячейке видно несколько выбранных пунктов. Если пользователь ничего не выбрал — ячейка пустая. Если в настройках нет вариантов — выбирать будет нечего.

Простой пример. Вы сделали колонку «Теги» и добавили варианты «Срочно», «Оплата», «Доставка». В строке заявки пользователь выбрал «Срочно» и «Оплата». Значит, по этой строке понятно: заявка срочная и связана с оплатой.

Если нужна формула. Этот пункт можно пропустить, если вы просто выбираете значения из списка. Формула ниже отвечает на вопрос: «выбрали ли в колонке Теги пункт Срочно?»

=ЕСЛИ(НАЙТИ("Срочно";Теги)>0;"Да";"Нет")

Если «Срочно» найдено — получится «Да», если нет — «Нет». Подробнее: НАЙТИ, ЕСЛИ.

Текст по шаблону (mask)

Когда выбирать. Когда все значения должны выглядеть одинаково: телефон, паспорт, код, номер договора.

Что настроить. В настройках укажите шаблон. Например, для телефона: +375 (xx) xxx-xx-xx.

Что делает пользователь. Вводит только нужные символы, а скобки, пробелы и дефисы подставляются сами.

+375 (29) 123-45-67
AB-12345
BY1234567

Что будет. Если пользователь попытается ввести неподходящий символ, поле его не примет. Это не ошибка: маска специально защищает от неправильного формата.

Если нужна формула. Значение можно обрабатывать как текст:

=ЛЕВСИМВ(Телефон;7)

Подробнее: ЛЕВСИМВ, ДЛСТР.

Файл (file)

Когда выбирать. Когда к строке нужно прикрепить документ, фото, скан, договор, счёт.

Что настроить. Выберите, как показывать файл: только название, название и размер, или другой режим из вашей версии интерфейса.

Что делает пользователь. Нажимает загрузку файла и выбирает файл на компьютере.

договор.pdf
счёт_май.xlsx
фото_объекта.jpg

Что будет. Файл прикрепится к строке. Если просто вставить ссылку текстом, это не станет файлом: файл нужно именно загрузить.

Формулы. Обычно файл не считают формулами. Если нужно хранить ссылку или номер документа — заведите отдельную текстовую колонку.

Интеграция модуля в интерфейс

Короткий рабочий пример на основе локального модуля nERP: что вызывается при init, что появляется в UI и что снять в dispose.

1. Как подключается модуль

Модуль — это JS-файл, который экспортирует функцию createModule(ctx).

Когда модуль запускается, хост вызывает init(). Внутри init() модуль обычно:

  • регистрирует свой источник через registerExtensionSource;
  • добавляет кнопку или пункт меню через registerContribution;
  • подписывается на нажатия через onAction.

Когда модуль отключается, хост вызывает dispose(). Внутри dispose() нужно снять подписки и удалить всё, что модуль добавил в интерфейс.

2. Рабочий пример

module.exports = function createModule(ctx) {
  const actionId = "ntp-module-nerplocal:hello";
  const contributionId = `${ctx.moduleId}:local-demo`;
  let offAction = null;
  let offLanguageChange = null;

  const translate = (key, fallback) => {
    const value = ctx.hostApi?.nerp?.t?.(key);
    if (typeof value === "string" && value && value !== key) {
      return value;
    }
    return fallback;
  };

  const getExtensionTitle = () =>
    translate("projectLocalModules.demo.sourceTitle", ctx.moduleId);

  const getContributionLabel = () =>
    translate("projectLocalModules.demo.label", ctx.moduleId);

  const getAlertMessage = () =>
    translate("projectLocalModules.demo.alert", actionId);

  const syncContribution = ({ initial = false } = {}) => {
    const contributionPayload = {
      id: contributionId,
      type: "menu_item",
      target: "LIST_CONTROLS_DROPDOWN",
      scope: "global",
      label: getContributionLabel(),
      icon: "none",
      action: actionId,
    };

    ctx.hostApi.nerp.registerExtensionSource({
      title: getExtensionTitle(),
      version: "0.1.0",
    });

    if (initial) {
      ctx.hostApi.nerp.registerContribution(contributionPayload);
      return;
    }

    ctx.hostApi.nerp.updateContribution({
      id: contributionId,
      moduleId: ctx.moduleId,
      patch: contributionPayload,
    });
  };

  return {
    init() {
      syncContribution({ initial: true });

      offAction = ctx.hostApi.nerp.onAction((detail) => {
        if (detail?.action !== actionId) {
          return;
        }
        ctx.hostApi.nerp.alert(getAlertMessage());
      });

      offLanguageChange =
        ctx.hostApi.nerp.onLanguageChange?.(() => {
          syncContribution();
        }) || null;
    },

    dispose() {
      if (typeof offAction === "function") {
        offAction();
        offAction = null;
      }

      if (typeof offLanguageChange === "function") {
        offLanguageChange();
        offLanguageChange = null;
      }

      ctx.hostApi.nerp.unregisterContribution({ id: contributionId });
      ctx.hostApi.nerp.unregisterExtensionSource();
    },
  };
};

3. Что делает этот код

Экспорт модуля

Файл экспортирует функцию createModule(ctx). Через ctx модуль получает доступ к API хоста и к своему moduleId.

actionId

actionId — это имя действия, по которому модуль потом понимает, что нажали именно его кнопку.

contributionId

contributionId — уникальный идентификатор добавленного элемента интерфейса.

syncContribution()

Эта функция собирает описание кнопки и либо добавляет её впервые, либо обновляет уже существующую.

В примере кнопка:

  • имеет тип menu_item;
  • вставляется в LIST_CONTROLS_DROPDOWN;
  • видна глобально через scope: "global";
  • по нажатию запускает действие actionId.

init()

При запуске модуля:

  • добавляется источник модуля;
  • добавляется кнопка;
  • подключается обработчик нажатия;
  • подключается обработчик смены языка, чтобы обновить подпись кнопки.

onAction()

В обработчик приходит объект detail. Модуль проверяет detail.action. Если это не его действие — ничего не делает. Если действие совпало — показывает alert.

onLanguageChange()

Если язык интерфейса поменялся, модуль заново вызывает syncContribution() и обновляет текст кнопки.

4. Через что модуль работает с интерфейсом

В обычном модуле nERP работа идёт через ctx.hostApi.nerp. Именно через этот объект вызываются:

  • registerExtensionSource() — зарегистрировать источник;
  • registerContribution() — добавить элемент интерфейса;
  • updateContribution() — обновить уже добавленный элемент;
  • onAction() — ловить нажатия;
  • onLanguageChange() — реагировать на смену языка;
  • alert() — показать простое сообщение;
  • unregisterContribution() — удалить элемент интерфейса;
  • unregisterExtensionSource() — удалить источник модуля.

Если это обычный модуль, тебе почти всегда нужен именно ctx.hostApi.nerp.

5. Что приходит при нажатии

При нажатии в обработчик onAction() приходит объект detail. На практике чаще всего достаточно поля action.

ctx.hostApi.nerp.onAction((detail) => {
  if (detail?.action !== actionId) {
    return;
  }

  ctx.hostApi.nerp.alert("Нажали кнопку модуля");
});

То есть обычный сценарий простой: сравнил detail.action со своим actionId и выполнил нужный код.

6. Как корректно отключать модуль

При отключении модуля нужно сделать три вещи:

  • снять обработчик нажатия;
  • снять обработчик смены языка, если он есть;
  • удалить добавленный элемент интерфейса и источник модуля.
dispose() {
  if (typeof offAction === "function") {
    offAction();
    offAction = null;
  }

  if (typeof offLanguageChange === "function") {
    offLanguageChange();
    offLanguageChange = null;
  }

  ctx.hostApi.nerp.unregisterContribution({ id: contributionId });
  ctx.hostApi.nerp.unregisterExtensionSource();
}

Если этого не сделать, в интерфейсе останется мусор: старая кнопка, старая подписка или дубли после повторного запуска.