R
Раскрой Панелей
🌐 Тонкий / Веб-клиент 🖥️ Толстый — UI ⚡ Толстый — UI + API 🤖 Без UI 🏭 On-Premise

🤖 Без UI — Автоматизация Автоматизация

⏱ 2–4 часа 📝 ~120 строк ObjectScript 🔑 API-ключ: обязателен 📅 Регламентное задание
Полностью автоматический режим — без HTML-поля, без участия менеджера. Регламентное задание 1С опрашивает новые заказы, отправляет расчёт через API, заполняет документы и синхронизирует склад. Подходит для высокой нагрузки и пакетной обработки.
Новый заказ в 1С
Рег.задание
POST /calculate
Результат в документ
Статус → issued
Когда подходит
  • Много заказов, ручной расчёт нерентабелен
  • Пакетная обработка в конце дня/недели
  • Нет UI для менеджера (только ERP-логика)
  • Автообновление склада без участия человека
  • Интеграция в существующий бизнес-процесс 1С
Ограничения
  • Менеджер не видит схему раскроя в 1С
  • Нужен толстый клиент (HTTP-запросы)
  • Требует тщательной настройки запроса данных
  • Для схем — открывать /production вручную
Схемы раскроя и PDF по-прежнему доступны на странице /production — пильщик видит всё без 1С.

Модуль «РаскройАвто» — только HTTP

Добавьте общий модуль с флагами Сервер. Клиентская часть не нужна.
РаскройАвто (Общий модуль, Сервер)
// ═══════════════════════════════════════════════════════════════
// РаскройАвто — headless API-интеграция (только сервер)
// ═══════════════════════════════════════════════════════════════

BASE_URL  = "https://raskroy.app";
API_TOKEN = "rsk_ВАШ_КЛЮЧ";
СТРАТЕГИЯ = "optimal";   // standard | optimal | liquid
РЕЖИМ     = "sandwich";  // sandwich | windowsill (по умолчанию сэндвич)

// ── Рассчитать раскрой и вернуть результат ───────────────────────
// Режим: "sandwich" — сэндвич-панели (лист 3000×1500, FFD + LNS)
//        "windowsill" — подоконники (рулон 6000мм, 1D-укладка по ширине)
&НаСервере
Функция Рассчитать(НомерЗаказа, ДеталиМассив, Стратегия = Неопределено, Режим = Неопределено) Экспорт

    Если Стратегия = Неопределено Тогда Стратегия = СТРАТЕГИЯ; КонецЕсли;
    Если Режим = Неопределено Тогда Режим = РЕЖИМ; КонецЕсли;

    ЧастиДеталей = Новый Массив;
    Счётчик = 1;
    Для Каждого Д Из ДеталиМассив Цикл
        П = Новый Структура;
        П.Вставить("id",  "P" + Счётчик);
        П.Вставить("w",  Д.Ширина);
        П.Вставить("h",  Д.Высота);
        П.Вставить("qty", Д.Количество);
        ЧастиДеталей.Добавить(П);
        Счётчик = Счётчик + 1;
    КонецЦикла;

    Тело = Новый Структура;
    Тело.Вставить("order_id",     НомерЗаказа);
    Тело.Вставить("strategy",     Стратегия);
    Тело.Вставить("cutting_mode", Режим);
    Тело.Вставить("parts",        ЧастиДеталей);

    Попытка
        Соединение = Новый HTTPСоединение("raskroy.app",,,,,, Новый ЗащищённоеСоединениеOpenSSL);
        Запрос = Новый HTTPЗапрос("/api/v1/calculate");
        Запрос.Заголовки.Вставить("Content-Type", "application/json");
        Запрос.Заголовки.Вставить("X-API-Key",    API_TOKEN);
        Запрос.УстановитьТелоИзСтроки(_ВJSON(Тело));
        Ответ = Соединение.ОтправитьДляОбработки(Запрос);

        Если Ответ.КодСостояния = 200 Тогда
            Возврат _ИзJSON(Ответ.ПолучитьТелоКакСтроку());
        ИначеЕсли Ответ.КодСостояния = 429 Тогда
            ВызватьИсключение "Превышен лимит запросов. Повторите позже.";
        Иначе
            ВызватьИсключение "API вернул ошибку: " + Ответ.КодСостояния;
        КонецЕсли;

    Исключение
        ЖурналРегистрации.Записать("РаскройАвто", УровеньЖурналаРегистрации.Ошибка,
            "Ошибка расчёта заказа " + НомерЗаказа + ": " + ОписаниеОшибки());
        Возврат Неопределено;
    КонецПопытки;

КонецФункции

// ── Обновить статус заказа ───────────────────────────────────────
&НаСервере
Процедура ОбновитьСтатус(ЗаказID, Статус, Контрагент = "") Экспорт
    Попытка
        Соединение = Новый HTTPСоединение("raskroy.app",,,,,, Новый ЗащищённоеСоединениеOpenSSL);
        Запрос = Новый HTTPЗапрос("/api/v1/orders/" + ЗаказID + "/status");
        Запрос.Заголовки.Вставить("Content-Type", "application/json");
        Запрос.Заголовки.Вставить("X-API-Key",    API_TOKEN);
        Запрос.УстановитьТелоИзСтроки(_ВJSON(
            Новый Структура("status,client_name", Статус, Контрагент)));
        Соединение.ВызватьHTTP(Запрос, "PATCH");
    Исключение
        ЖурналРегистрации.Записать("РаскройАвто",, ОписаниеОшибки());
    КонецПопытки;
КонецПроцедуры

// ── Получить данные расчёта (для заполнения счёта из рег.задания) ─
&НаСервере
Функция ПолучитьИнвойс(ЗаказID) Экспорт
    Попытка
        Соединение = Новый HTTPСоединение("raskroy.app",,,,,, Новый ЗащищённоеСоединениеOpenSSL);
        Запрос = Новый HTTPЗапрос("/api/v1/orders/" + ЗаказID + "/invoice");
        Запрос.Заголовки.Вставить("X-API-Key", API_TOKEN);
        Ответ = Соединение.Получить(Запрос);
        Если Ответ.КодСостояния = 200 Тогда
            Возврат _ИзJSON(Ответ.ПолучитьТелоКакСтроку());
        КонецЕсли;
    Исключение КонецПопытки;
    Возврат Неопределено;
КонецФункции

// ── JSON helpers ─────────────────────────────────────────────────
&НаСервере
Функция _ВJSON(О)
    З = Новый ЗаписьJSON; З.УстановитьСтроку(); ЗаписатьJSON(З, О); Возврат З.Закрыть();
КонецФункции
&НаСервере
Функция _ИзJSON(С)
    Ч = Новый ЧтениеJSON; Ч.УстановитьСтроку(С); Возврат ПрочитатьJSON(Ч);
КонецФункции

Регламентное задание — авторасчёт новых заказов

Запускается по расписанию (например, каждые 15 минут). Проверяет новые заказы, считает раскрой, обновляет документы.
РегЗадание.АвторасчётРаскроя
// Метод регламентного задания — запускать каждые 15–30 минут
&НаСервере
Процедура ВыполнитьАвторасчёт() Экспорт

    // 1. Выбрать счета без расчёта раскроя (доп.реквизит НомерРаскроя пуст)
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ
    |    Сч.Ссылка КАК Ссылка,
    |    Сч.Контрагент.Наименование КАК Контрагент,
    |    Сч.Товары.(
    |        Номенклатура.Наименование КАК Наименование,
    |        Номенклатура.Ширина       КАК Ширина,
    |        Номенклатура.Высота       КАК Высота,
    |        Количество                КАК Количество
    |    )
    |ИЗ Документ.СчётПокупателю КАК Сч
    |ГДЕ Сч.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыСчётов.Новый)
    |    И Сч.НомерРаскроя = """"
    |    И Сч.Проведён = ИСТИНА
    |УПОРЯДОЧИТЬ ПО Сч.Дата УБЫВ";

    Выборка = Запрос.Выполнить().Выбрать();

    Пока Выборка.Следующий() Цикл

        НомерЗаказа = Строка(Выборка.Ссылка);

        // 2. Собрать детали из строк счёта
        Детали = Новый Массив;
        СтрокиТовары = Выборка.Товары.Выбрать();
        Пока СтрокиТовары.Следующий() Цикл
            Если СтрНайти(НРег(СтрокиТовары.Наименование), "сэндвич") > 0 Тогда
                Детали.Добавить(Новый Структура("Ширина,Высота,Количество",
                    СтрокиТовары.Ширина, СтрокиТовары.Высота, СтрокиТовары.Количество));
            КонецЕсли;
        КонецЦикла;
        Если Детали.Количество() = 0 Тогда Продолжить; КонецЕсли;

        // 3. Вызвать API расчёта
        Результат = РаскройАвто.Рассчитать(НомерЗаказа, Детали);
        Если Результат = Неопределено Тогда Продолжить; КонецЕсли;

        // 4. Записать результат в доп.реквизит счёта
        ОбъектСчёта = Выборка.Ссылка.ПолучитьОбъект();
        С            = Результат.summary;
        ОбъектСчёта.НомерРаскроя    = НомерЗаказа;
        ОбъектСчёта.ЛистовРаскрой   = С.sheets_used;
        ОбъектСчёта.КПДРаскрой      = С.efficiency_pct;
        ОбъектСчёта.Записать(РежимЗаписиДокумента.Запись);

        // 5. Обновить статус на сервисе
        РаскройАвто.ОбновитьСтатус(НомерЗаказа, "issued", Выборка.Контрагент);

        ЖурналРегистрации.Записать("РаскройАвто",, "Рассчитан: "+НомерЗаказа+" — "+С.sheets_used+" листов");

    КонецЦикла;

КонецПроцедуры
Добавьте в документ «Счёт покупателю» дополнительные реквизиты: НомерРаскроя (Строка 50), ЛистовРаскрой (Число), КПДРаскрой (Число 5.2).

Автоматическое переключение статуса при оплате

Добавьте в обработчик события «Счёт оплачен» (подписка на событие или процедура проведения):
При регистрации оплаты счёта
// Вызывается при проведении платёжного документа
&НаСервере
Процедура ОбработатьОплатуСчёта(НомерСчёта, Контрагент)
    // Переводим заказ в статус "оплачен"
    РаскройАвто.ОбновитьСтатус(НомерСчёта, "paid", Строка(Контрагент));
КонецПроцедуры

// После подтверждения производства:
Процедура ОтправитьВПроизводство(НомерСчёта, Контрагент, Примечание = "")
    Тело = Новый Структура("status,client_name,production_note",
        "in_production", Строка(Контрагент), Примечание);
    // ... HTTP PATCH /api/v1/orders/НомерСчёта/status
    РаскройАвто.ОбновитьСтатус(НомерСчёта, "in_production", Строка(Контрагент));
КонецПроцедуры

Тестирование