Собственные узлы: реальный выбор и локальный расчёт 1000 → 500 → 1000

Учебные задачи

Пройти N/D/N через настоящий ordinary NodeList и поле NodeRef, проверить фактическое позиционирование/quick choice/стандартную картинку и полный неизменённый узловой источник. Обмен не выполняется.

Где и как запускать

Полный client-only общий модуль УзлыВыбор85; собственная ordinary File CF/Windows thick client; никаких RPC/сообщений.

Подготовка

  1. Только будущий опыт в собственной совершенно новой пустой File ИБ C:\1c-labs\OwnNodeAddressbook85_6b0a5f95-cd23-4a6d-9e08-936170b5a4bd\IB на отдельном Windows стенде. Не переиспользуйте и не очищайте существующий путь. Платформа8.5.1.1343. Здесь никакие CF/ИБ/узлы/каталоги/окна не создавались;1С не запускалась. Это локальный адресный справочник и расчёт в памяти, НЕ реализация обмена.

  2. Конфигурация УчебныеУзлы85: совместимость НеИспользовать; ОсновнойРежимЗапуска ОбычноеПриложение. В Конфигураторе Сервис → Параметры → Общие → Редактирование конфигурации для режима запуска выберите «Управляемое приложение и обычное приложение». Это настройка редактора, не свойство SupportedRunModes. Только один ПланОбмена Узлы85, одна обработка Пульт85, два общих модуля и одна роль; других прикладных объектов/общих реквизитов/разделителей/расширений/подписок/заданий нет.

  3. ПланОбмена Узлы85: РаспределеннаяИнформационнаяБазаНет; Состав пустой. Ничего в состав не включайте, авторегистрацию изменений не настраивайте, не вызывайте обмен/регистрацию/работу сообщений. Код Строка12, Наименование80, уникальностьДа. Без табличных частей, история данных выключена. Два реквизита: Маркер85 только Строка36; Коэффициент85 только Число10,2. Состав читается через metadata.Состав.Количество, не недокументированный manager.Состав; readonly контейнер не изменяется.

  4. ДО установки startup и запрета записи вручную заполните ровно3 сохранённых узла. Предопределённый текущий узел этого нового плана — actual ПланыОбмена.Узлы85.ЭтотУзел(), не UUID из инструкции: откройте его стандартную форму и задайте SELF85/Текущий/Коэффициент85=0. Создайте два своих периферийных узла N85/Обычный/1 и D85/Половина/0.5. Маркер85 у всех6b0a5f95-cd23-4a6d-9e08-936170b5a4bd, ПометкаУдаленияFalse, НомерОтправленного0, НомерПринятого0. Текущим является только actualSELFRef; свойство ЭтотУзел у объектов не переключайте. ДатаОбмена/ВерсияДанных читаются фактически, их значения по умолчанию не угадываются и не присваиваются. Если current/ref/counters/полный source не совпали, опыт прекращается без исправления неизвестного узла.

  5. Своё единственное имя пользователя Узлы85Ученик и единственная роль Узлы85: чтение/просмотр/ввод по строке/добавление/изменение своего плана, использование своей обработки и АктивныеПользователи для проверки одного подключения; без RLS/привилегированности/админсервисов. Права добавления не означают разрешение программы записывать узлы. После ручной начальной fixture вставьте NODE_MODULE целиком в ПланыОбмена → Узлы85 → Модуль объекта: native ПередЗаписью1 безусловно ОтказTrue во всех его контекстах. Не ставьте этот запрет до ручного заполнения. Все остальные объектные/менеджерные модули пустые. Закройте Конфигуратор и первоначальный клиент; в будущем опыте оставьте одно собственное клиентское подключение.

  6. ОбщиеМодули УзлыИсточник85 и УзлыВыбор85: ГлобальныйНет, КлиентОбычноеПриложениеДа, КлиентУправляемоеПриложениеНет, СерверНет, ВнешнееСоединениеНет, ПривилегированныйНет, повторное использованиеНеИспользовать. Полный SOURCE в первый, полный SELECTOR во второй. SOURCE проверяет полный источник и создаёт конкретную смету в памяти: количества1/1/2 по цене250, база1000; никаких неизвестных объектов или произвольных файлов. Broad object BeforeWrite не вызывает эти client-only помощники.

  7. ПланыОбмена → Узлы85 → Формы: конструктором создайте ОБЫЧНУЮ основную форму списка Список85. Основной реквизит Список85 только ПланОбменаСписок.Узлы85; табличное поле Узлы85 с Данные=Список85, колонка Наименование с Данные=Наименование, ТолькоПросмотрДа. МножественныйВыборНет. Никаких собственных модулей/обмена/команд записи списка. Native расширения доступны именно compiled списку и его реальной колонке, не новым пустым типам.

  8. В том же плане конструктором создайте обычную основную форму узла Узел85. Основной реквизит Узел85 только ПланОбменаОбъект.Узлы85. Объектные поля для просмотра, без стандартных Записать/ОК. Добавьте Согласие85 Булево/флажок Данные=Согласие85 с начальным False, Статус85 Строка500 readonly и кнопку ПроверитьЗапрет85. Полный NODE_FORM в модуль: ПриОткрытии0→ПриОткрытии; ПередЗаписью1→ПередЗаписью, кнопка.Нажатие с первым actualКнопка→ПроверитьЗапрет85. Native форму реального нового объекта создаёт GetForm, основной реквизит содержит именно переданную копию.

  9. Обработки → Пульт85 → Формы: обычная основная форма Пульт85. Реквизиты МаркерПульта85 Строка36, Остановлен85 Булево, Этап85 Число2,0, ВыборУзла85 только ПланОбменаСсылка.Узлы85, Статус85 Строка500 readonly. Паспорт85 — частная Перем модуля HUB, не новый реквизит метаданных; другие собственные модули получают эту созданную SOURCE структуру через реальную экспортную функцию ПолучитьПаспорт85(). Служебные реквизиты не редактировать. ПолеВвода ВыборУзла85: Имя/Данные точно ВыборУзла85, ввод по строке Код/Наименование; кнопки Выбрать85 и Черновик85. Полный HUB: ПриОткрытии0; ОбработкаВыбора2; поле.ПриИзменении с actual первым Элемент→УзелПриИзменении85; каждая кнопка.Нажатие1 на одноимённую процедуру. Child forms принадлежат пульту, не полю ввода: pointer сохраняется до Open/native событий.

  10. Полный APPLICATION в Модуль обычного приложения, native ПриНачалеРаботыСистемы0. Обновите только свою учебную CF после ручной проверки всех имён/типов/связей; затем один толстый обычный клиент. Через Выбрать85 в действительном списке выберите N85, D85, N85. Позиционирование ПараметрТекущаяСтрока применяется при открытии, не означает автоматически сделанный выбор. Отмена не продвигает этап. Результаты1000/500/1000 вычислены по фактическому сохранённому коэффициенту и трём реально созданным строкам памяти; это НЕ номера/суммы отправленных сообщений.

  11. После N/D/N кнопка Черновик85 вызывает native Copy собственного N85, который НЕ записывает объект. Основная форма получает тот же новый объект; copy ref=N85, basis ref=actual текущийSELFRef. Это осмысленный паспорт происхождения черновика, НЕ команда ввода на основании/обмена. Только у этой несохранённой копии задаётся DRAFT85/Черновик/0.75; расчёт750, сохранённые3 узла остаются прежними. Не копируйте текущий узел и не меняйте номера сообщений/свойствоЭтотУзел. Стандартный значок списка — фактическая native policy; имена/пиксели картинок не угадываются.

  12. Проверка запрета записи — отдельное явное согласие, флажокFalse по умолчанию. После согласия native WriteInForm0 должен быть отклонён настоящим Form.BeforeWrite1 (ОтказTrue); Object.BeforeWrite1 дополнительно запрещает ширококонтекстную запись. False НЕ успешное сохранение: перечитывается весь паспорт/версии/даты, а форма и пульт остаются СТОП без повторной попытки. Exception или неожиданный True означают неизвестный исход: СТОП/rethrow, никакого слепого rollback/удаления/повтора. Закрытие несохранённого буфера без согласия не является программной записью. Ни callback, ни тест отказа не вызывайте вручную как поддельное событие.

#Если ТолстыйКлиентОбычноеПриложение Тогда

Функция ПодготовитьСписок85(Пульт) Экспорт
    Пульт.ПроверитьПульт85();
    Паспорт = Пульт.ПолучитьПаспорт85();
    УзлыИсточник85.ПроверитьСохранность85(Паспорт);
    Поле = Пульт.ЭлементыФормы.ВыборУзла85;
    Если ТипЗнч(Поле) <> Тип("ПолеВвода") Или Поле.Имя <> "ВыборУзла85" Или Поле.Данные <> "ВыборУзла85" Тогда
        ВызватьИсключение "Нужно собственное поле конкретного NodeRef";
    КонецЕсли;
    Поле.БыстрыйВыбор = Истина;
    Ключ = Новый УникальныйИдентификатор;
    Форма = ПланыОбмена.Узлы85.ПолучитьФормуСписка("Список85", Пульт, Ключ);
    Если Форма = Неопределено Или ТипЗнч(Форма) <> Тип("Форма") Или Форма.Открыта() Или Форма.ВладелецФормы <> Пульт Или Форма.КлючУникальности <> Ключ Тогда
        ВызватьИсключение "Не получена actual новая собственная ordinary форма списка";
    КонецЕсли;
    Таблица = Форма.ЭлементыФормы.Узлы85;
    Если ТипЗнч(Таблица) <> Тип("ТабличноеПоле") Или Таблица.Данные <> "Список85" Или Таблица.Значение <> Форма.Список85
        Или ТипЗнч(Таблица.Значение) <> Тип("ПланОбменаСписок.Узлы85") Тогда
        ВызватьИсключение "Нужен actual compiled список этого плана, не ValueTable";
    КонецЕсли;
    Колонка = Таблица.Колонки.Найти("Наименование");
    Если Колонка = Неопределено Или ТипЗнч(Колонка) <> Тип("КолонкаТабличногоПоля") Или Колонка.Данные <> "Наименование" Тогда
        ВызватьИсключение "Не подтверждена колонка настоящего NodeList";
    КонецЕсли;
    Колонка.ОтображатьСтандартнуюКартинку = Истина;
    Форма.РежимВыбора = Истина;
    Форма.ТолькоПросмотр = Истина;
    Форма.МножественныйВыбор = Ложь;
    Форма.ПараметрТекущаяСтрока = ?(Пульт.Этап85 = 2, Паспорт.Половина, Паспорт.Обычный);
    Если Не Поле.БыстрыйВыбор Или Не Колонка.ОтображатьСтандартнуюКартинку Или Не Форма.РежимВыбора Или Не Форма.ТолькоПросмотр
        Или Форма.МножественныйВыбор Или Форма.ПараметрТекущаяСтрока <> ?(Пульт.Этап85 = 2, Паспорт.Половина, Паспорт.Обычный) Тогда
        ВызватьИсключение "Не прочитаны обратно actual политики выбора и позиционирования";
    КонецЕсли;
    Возврат Форма;
КонецФункции

Процедура РассчитатьВыбор85(Пульт) Экспорт
    Пульт.ПроверитьПульт85();
    Если Пульт.Этап85 < 1 Или Пульт.Этап85 > 3 Тогда
        ВызватьИсключение "Маршрут выбора уже завершён";
    КонецЕсли;
    Паспорт = Пульт.ПолучитьПаспорт85();
    УзлыИсточник85.ПроверитьСохранность85(Паспорт);
    Ссылка = Пульт.ВыборУзла85;
    Если ТипЗнч(Ссылка) <> Тип("ПланОбменаСсылка.Узлы85") Или Ссылка.Пустая() Или Ссылка = Паспорт.Этот
        Или Ссылка <> ?(Пульт.Этап85 = 2, Паспорт.Половина, Паспорт.Обычный) Тогда
        Пульт.Статус85 = "Выберите вручную " + ?(Пульт.Этап85 = 2, "D85/Половина", "N85/Обычный") + ". Текущий или посторонний узел не вычисляется.";
        Возврат;
    КонецЕсли;
    Объект = Ссылка.ПолучитьОбъект();
    Если Объект = Неопределено Или ТипЗнч(Объект) <> Тип("ПланОбменаОбъект.Узлы85") Или Объект.Ссылка <> Ссылка Или Объект.ЭтотУзел
        Или Объект.Маркер85 <> "6b0a5f95-cd23-4a6d-9e08-936170b5a4bd" Или Объект.Коэффициент85 <> ?(Пульт.Этап85 = 2, 0.5, 1) Тогда
        ВызватьИсключение "Не подтвердился actual собственный выбранный объект";
    КонецЕсли;
    Сумма = УзлыИсточник85.Рассчитать85(Объект.Коэффициент85);
    Если Сумма <> ?(Пульт.Этап85 = 2, 500, 1000) Тогда
        ВызватьИсключение "Реальный выбор и реальная смета не дали 1000/500/1000";
    КонецЕсли;
    УзлыИсточник85.ПроверитьСохранность85(Паспорт);
    Пульт.Статус85 = "Выбран свой узел, локальная смета × его коэффициент: " + Формат(Сумма, "ЧГ=0;ЧДЦ=2") + ". Никакого обмена не было.";
    Пульт.Этап85 = Пульт.Этап85 + 1;
КонецПроцедуры

#КонецЕсли
Полный паспорт всех сохранённых узлов и собственная смета

ОбщиеМодули → УзлыИсточник85 → Модуль, целиком

ClientOrdinaryДа/ServerНет; только чтение своей CF и расчёт памяти

#Если ТолстыйКлиентОбычноеПриложение Тогда

Функция Прочитать85() Экспорт
    Если СтрокаСоединенияИнформационнойБазы() <> "File=""C:\1c-labs\OwnNodeAddressbook85_6b0a5f95-cd23-4a6d-9e08-936170b5a4bd\IB"";" Или Метаданные.РежимСовместимости <> Метаданные.СвойстваОбъектов.РежимСовместимости.НеИспользовать Или Метаданные.ОсновнойРежимЗапуска <> РежимЗапускаКлиентскогоПриложения.ОбычноеПриложение Или ТранзакцияАктивна() Тогда
        ВызватьИсключение "Только своя новая File ИБ без совместимости и активной транзакции";
    КонецЕсли;
    Если Метаданные.ПланыОбмена.Количество() <> 1 Или Метаданные.Обработки.Количество() <> 1 Или Метаданные.ОбщиеМодули.Количество() <> 2 Или Метаданные.Роли.Количество() <> 1 Или Метаданные.Справочники.Количество() <> 0 Или Метаданные.Документы.Количество() <> 0 Или Метаданные.Константы.Количество() <> 0 Или Метаданные.Перечисления.Количество() <> 0 Или Метаданные.ПланыВидовХарактеристик.Количество() <> 0 Или Метаданные.ПланыВидовРасчета.Количество() <> 0 Или Метаданные.ПланыСчетов.Количество() <> 0 Или Метаданные.РегистрыСведений.Количество() <> 0 Или Метаданные.РегистрыНакопления.Количество() <> 0 Или Метаданные.РегистрыБухгалтерии.Количество() <> 0 Или Метаданные.РегистрыРасчета.Количество() <> 0 Или Метаданные.БизнесПроцессы.Количество() <> 0 Или Метаданные.Задачи.Количество() <> 0 Или Метаданные.Отчеты.Количество() <> 0 Или Метаданные.КритерииОтбора.Количество() <> 0 Или Метаданные.ОбщиеРеквизиты.Количество() <> 0 Или Метаданные.ПараметрыСеанса.Количество() <> 0 Или Метаданные.ПодпискиНаСобытия.Количество() <> 0 Или Метаданные.РегламентныеЗадания.Количество() <> 0 Или Метаданные.ХранилищаНастроек.Количество() <> 0 Или Метаданные.ВнешниеИсточникиДанных.Количество() <> 0 Тогда
        ВызватьИсключение "Чужая прикладная схема запрещена";
    КонецЕсли;
    Если РасширенияКонфигурации.Получить(, ИсточникРасширенийКонфигурации.БазаДанных).Количество() <> 0
        Или РасширенияКонфигурации.Получить(, ИсточникРасширенийКонфигурации.СеансАктивные).Количество() <> 0
        Или РасширенияКонфигурации.Получить(, ИсточникРасширенийКонфигурации.СеансОтключенные).Количество() <> 0 Тогда
        ВызватьИсключение "Расширения не допускаются";
    КонецЕсли;
    МД = Метаданные.ПланыОбмена.Найти("Узлы85");
    Если МД = Неопределено Или МД.РаспределеннаяИнформационнаяБаза Или МД.Состав.Количество() <> 0 Или МД.ТабличныеЧасти.Количество() <> 0
        Или МД.Реквизиты.Количество() <> 2 Или МД.ДлинаКода <> 12 Или МД.ДлинаНаименования <> 80 Тогда
        ВызватьИсключение "Требуется свой НЕ-RIB план с пустым составом и двумя реквизитами";
    КонецЕсли;
    Маркер = МД.Реквизиты.Найти("Маркер85"); Коэффициент = МД.Реквизиты.Найти("Коэффициент85");
    Если Маркер = Неопределено Или Коэффициент = Неопределено Или Маркер.Тип.Типы().Количество() <> 1
        Или Не Маркер.Тип.СодержитТип(Тип("Строка")) Или Маркер.Тип.КвалификаторыСтроки.Длина <> 36
        Или Коэффициент.Тип.Типы().Количество() <> 1 Или Не Коэффициент.Тип.СодержитТип(Тип("Число"))
        Или Коэффициент.Тип.КвалификаторыЧисла.Разрядность <> 10 Или Коэффициент.Тип.КвалификаторыЧисла.РазрядностьДробнойЧасти <> 2 Тогда
        ВызватьИсключение "Не подтверждены конкретные типы собственных полей";
    КонецЕсли;
    Пользователь = ПользователиИнформационнойБазы.ТекущийПользователь();
    Если Пользователь = Неопределено Или Пользователь.Имя <> "Узлы85Ученик" Или Не РольДоступна("Узлы85") Тогда
        ВызватьИсключение "Нужен только свой учебный пользователь";
    КонецЕсли;
    Соединения = ПолучитьСоединенияИнформационнойБазы();
    Если ТипЗнч(Соединения) <> Тип("Массив") Или Соединения.Количество() <> 1 Тогда
        ВызватьИсключение "Оставьте ровно одно своё подключение";
    КонецЕсли;
    Если Соединения[0].НомерСоединения <> НомерСоединенияИнформационнойБазы() Или Соединения[0].Пользователь.УникальныйИдентификатор <> Пользователь.УникальныйИдентификатор Тогда
        ВызватьИсключение "Подключение не совпало с текущим своим пользователем";
    КонецЕсли;
    Этот = ПланыОбмена.Узлы85.ЭтотУзел();
    Если ТипЗнч(Этот) <> Тип("ПланОбменаСсылка.Узлы85") Или Этот.Пустая() Тогда
        ВызватьИсключение "Native manager не предоставил собственный текущий узел";
    КонецЕсли;
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ Ссылка,Код,Наименование,ПометкаУдаления,НомерОтправленного,НомерПринятого,Маркер85,Коэффициент85 ИЗ ПланОбмена.Узлы85";
    Строки = Запрос.Выполнить().Выгрузить();
    Если Строки.Количество() <> 3 Или Строки.Колонки.Количество() <> 8 Или Строки.Итог("Коэффициент85") <> 1.5 Тогда
        ВызватьИсключение "Нужен полный источник из текущего и двух собственных периферийных узлов";
    КонецЕсли;
    Дополнительно = Новый ТаблицаЗначений;
    Дополнительно.Колонки.Добавить("Ссылка", Новый ОписаниеТипов("ПланОбменаСсылка.Узлы85"));
    Дополнительно.Колонки.Добавить("Версия", Новый ОписаниеТипов("Строка"));
    Дополнительно.Колонки.Добавить("ДатаОбмена", Новый ОписаниеТипов("Дата"));
    Обычный = Неопределено; Половина = Неопределено; Проверенные = Новый Массив;
    Для Каждого Р Из Строки Цикл
        Если ТипЗнч(Р.Ссылка) <> Тип("ПланОбменаСсылка.Узлы85") Или Р.Ссылка.Пустая() Или Проверенные.Найти(Р.Ссылка) <> Неопределено
            Или Р.ПометкаУдаления Или Р.НомерОтправленного <> 0 Или Р.НомерПринятого <> 0 Или Р.Маркер85 <> "6b0a5f95-cd23-4a6d-9e08-936170b5a4bd" Тогда
            ВызватьИсключение "Чужой/повторный узел или ненулевые номера сообщений";
        КонецЕсли;
        Если Р.Ссылка = Этот И Р.Код = "SELF85" И Р.Наименование = "Текущий" И Р.Коэффициент85 = 0 Тогда
        ИначеЕсли Р.Ссылка <> Этот И Р.Код = "N85" И Р.Наименование = "Обычный" И Р.Коэффициент85 = 1 И Обычный = Неопределено Тогда
            Обычный = Р.Ссылка;
        ИначеЕсли Р.Ссылка <> Этот И Р.Код = "D85" И Р.Наименование = "Половина" И Р.Коэффициент85 = 0.5 И Половина = Неопределено Тогда
            Половина = Р.Ссылка;
        Иначе
            ВызватьИсключение "Лишний/подменённый узел или коэффициент";
        КонецЕсли;
        Объект = Р.Ссылка.ПолучитьОбъект();
        Если Объект = Неопределено Или ТипЗнч(Объект) <> Тип("ПланОбменаОбъект.Узлы85") Или Объект.Метаданные() <> МД
            Или Объект.Ссылка <> Р.Ссылка Или Объект.Код <> Р.Код Или Объект.Наименование <> Р.Наименование Или Объект.ПометкаУдаления <> Р.ПометкаУдаления
            Или Объект.НомерОтправленного <> Р.НомерОтправленного Или Объект.НомерПринятого <> Р.НомерПринятого
            Или Объект.Маркер85 <> Р.Маркер85 Или Объект.Коэффициент85 <> Р.Коэффициент85 Или Объект.ЭтотУзел <> (Р.Ссылка = Этот)
            Или ТипЗнч(Объект.ВерсияДанных) <> Тип("Строка") Или ТипЗнч(Объект.ДатаОбмена) <> Тип("Дата") Тогда
            ВызватьИсключение "Все actual поля сохранённого объекта должны совпасть с полным источником";
        КонецЕсли;
        Д = Дополнительно.Добавить(); Д.Ссылка = Р.Ссылка; Д.Версия = Объект.ВерсияДанных; Д.ДатаОбмена = Объект.ДатаОбмена;
        Проверенные.Добавить(Р.Ссылка);
    КонецЦикла;
    Если Проверенные.Найти(Этот) = Неопределено Или Обычный = Неопределено Или Половина = Неопределено Или Обычный = Половина Тогда
        ВызватьИсключение "Не подтверждены все три различные реальные ссылки";
    КонецЕсли;
    Возврат Новый Структура("Этот,Обычный,Половина,Строки,Дополнительно", Этот, Обычный, Половина, Строки, Дополнительно);
КонецФункции

Процедура ПроверитьСохранность85(До) Экспорт
    После = Прочитать85();
    Если До.Этот <> После.Этот Или До.Обычный <> После.Обычный Или До.Половина <> После.Половина Или До.Строки.Количество() <> 3 Или До.Дополнительно.Количество() <> 3 Тогда
        ВызватьИсключение "Заменены actual ссылки или целый исходный паспорт";
    КонецЕсли;
    Для Каждого Р Из До.Строки Цикл
        Факт = После.Строки.НайтиСтроки(Новый Структура("Ссылка", Р.Ссылка));
        Если Факт.Количество() <> 1 Тогда
            ВызватьИсключение "Исчезла собственная строка";
        КонецЕсли;
        Для Каждого Колонка Из До.Строки.Колонки Цикл
            Если Р[Колонка.Имя] <> Факт[0][Колонка.Имя] Тогда
                ВызватьИсключение "Изменилось поле сохранённого узла " + Колонка.Имя;
            КонецЕсли;
        КонецЦикла;
    КонецЦикла;
    Для Каждого Р Из До.Дополнительно Цикл
        Факт = После.Дополнительно.НайтиСтроки(Новый Структура("Ссылка", Р.Ссылка));
        Если Факт.Количество() <> 1 Или Факт[0].Версия <> Р.Версия Или Факт[0].ДатаОбмена <> Р.ДатаОбмена Тогда
            ВызватьИсключение "Изменились фактическая версия или дата обмена своего узла";
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Функция Рассчитать85(Коэффициент) Экспорт
    Если ТипЗнч(Коэффициент) <> Тип("Число") Или Коэффициент < 0 Или Коэффициент > 1 Тогда
        ВызватьИсключение "Нужен свой числовой коэффициент";
    КонецЕсли;
    Смета = Новый ТаблицаЗначений;
    Смета.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));
    Смета.Колонки.Добавить("Цена", Новый ОписаниеТипов("Число"));
    Для Индекс = 0 По 2 Цикл
        Р = Смета.Добавить(); Р.Количество = ?(Индекс = 2, 2, 1); Р.Цена = 250;
    КонецЦикла;
    Сумма = 0;
    Для Каждого Р Из Смета Цикл
        Сумма = Сумма + Р.Количество * Р.Цена * Коэффициент;
    КонецЦикла;
    Если Смета.Количество() <> 3 Или Сумма <> 1000 * Коэффициент Тогда
        ВызватьИсключение "Независимая арифметика трёх собственных строк не совпала";
    КонецЕсли;
    Возврат Сумма;
КонецФункции

#КонецЕсли
Полная форма собственной несохранённой копии и отказ записи

ПланыОбмена → Узлы85 → Формы → Узел85 → Модуль

Толстый ordinary клиент; настоящие BeforeWrite1/OnOpen0/Click1

Перем Подготовлен85, Стоп85;

Процедура ПодготовитьЧерновик85() Экспорт
    Если Подготовлен85 <> Неопределено Тогда
        ВызватьИсключение "Повторный initializer не снимает СТОП";
    КонецЕсли;
    Подготовлен85 = Ложь;
    Стоп85 = Истина;
    Пульт = ВладелецФормы;
    Пульт.ПроверитьЧерновик85(ЭтаФорма);
    УзлыИсточник85.ПроверитьСохранность85(Пульт.ПолучитьПаспорт85());
    Если ТипЗнч(Узел85) <> Тип("ПланОбменаОбъект.Узлы85") Или Не Узел85.ЭтоНовый() Или Узел85.ЭтотУзел
        Или Узел85.Маркер85 <> "6b0a5f95-cd23-4a6d-9e08-936170b5a4bd" Или Узел85.Коэффициент85 <> 1 Тогда
        ВызватьИсключение "Нужна новая native несохранённая копия собственного N85";
    КонецЕсли;
    Узел85.Код = "DRAFT85"; Узел85.Наименование = "Черновик"; Узел85.Коэффициент85 = 0.75;
    Паспорт = Пульт.ПолучитьПаспорт85();
    ЭтаФорма.ПараметрОбъектКопирования = Паспорт.Обычный;
    ЭтаФорма.ПараметрОснование = Паспорт.Этот;
    Согласие85 = Ложь;
    ПроверитьЧерновик85();
    Сумма = УзлыИсточник85.Рассчитать85(Узел85.Коэффициент85);
    Если Сумма <> 750 Тогда
        ВызватьИсключение "Черновой коэффициент не дал750 по действительной собственной смете";
    КонецЕсли;
    Статус85 = "Черновик0.75: локальная смета750. Сохранённые3 узла не изменились. Запись всегда запрещена.";
    Подготовлен85 = Истина;
    Стоп85 = Ложь;
КонецПроцедуры

Процедура ПроверитьЧерновик85()
    Пульт = ВладелецФормы;
    Пульт.ПроверитьЧерновик85(ЭтаФорма);
    Паспорт = Пульт.ПолучитьПаспорт85();
    УзлыИсточник85.ПроверитьСохранность85(Паспорт);
    Если ТипЗнч(Узел85) <> Тип("ПланОбменаОбъект.Узлы85") Или Не Узел85.ЭтоНовый() Или Узел85.ЭтотУзел Или Узел85.ПометкаУдаления
        Или Узел85.Код <> "DRAFT85" Или Узел85.Наименование <> "Черновик" Или Узел85.Коэффициент85 <> 0.75
        Или Узел85.Маркер85 <> "6b0a5f95-cd23-4a6d-9e08-936170b5a4bd" Или Узел85.НомерОтправленного <> 0 Или Узел85.НомерПринятого <> 0
        Или ЭтаФорма.ПараметрОбъектКопирования <> Паспорт.Обычный Или ЭтаФорма.ПараметрОснование <> Паспорт.Этот Тогда
        ВызватьИсключение "Не подтвердились actual черновик/copy/basis и нулевые номера сообщений";
    КонецЕсли;
КонецПроцедуры

Процедура ПриОткрытии()
    Если Подготовлен85 <> Истина Или Стоп85 <> Ложь Тогда
        ВызватьИсключение "Не подготовлен свой черновик или предыдущий исход неизвестен";
    КонецЕсли;
    ПроверитьЧерновик85();
КонецПроцедуры

Процедура ПроверитьЗапрет85(Кнопка)
    Если Кнопка <> ЭлементыФормы.ПроверитьЗапрет85 Или Стоп85 <> Ложь Тогда
        ВызватьИсключение "Только одно собственное явно подтверждённое испытание запрета";
    КонецЕсли;
    Если ТипЗнч(Согласие85) <> Тип("Булево") Или Не Согласие85 Тогда
        Возврат;
    КонецЕсли;
    ПроверитьЧерновик85();
    Стоп85 = Истина;
    ВладелецФормы.Остановлен85 = Истина;
    Согласие85 = Ложь;
    Попытка
        Результат = ЭтаФорма.ЗаписатьВФорме();
        Если ТипЗнч(Результат) <> Тип("Булево") Или Результат Тогда
            ВызватьИсключение "Неожиданная успешная запись: СТОП, не исправлять/не повторять";
        КонецЕсли;
        УзлыИсточник85.ПроверитьСохранность85(ВладелецФормы.ПолучитьПаспорт85());
        Если Не Узел85.ЭтоНовый() Тогда
            ВызватьИсключение "Черновик перестал быть новым: СТОП";
        КонецЕсли;
        Статус85 = "Native WriteInForm=False, полный сохранённый паспорт неизменён. Это отказ, не успешное сохранение. Пульт/форма остаются СТОП; повторной попытки нет.";
    Исключение
        Стоп85 = Истина;
        ВладелецФормы.Остановлен85 = Истина;
        Статус85 = "СТОП: исход неизвестен; нет автоматического отката, очистки или повтора.";
        ВызватьИсключение;
    КонецПопытки;
КонецПроцедуры

Процедура ПередЗаписью(Отказ)
    Отказ = Истина;
КонецПроцедуры
Полный реальный пульт и доставка событий выбора

Обработки → Пульт85 → Формы → Пульт85 → Модуль

Толстый ordinary клиент; ChoiceProcessing2/OnChange1/Click1

Перем Инициализирован85, СвойСписок85, СвойЧерновик85, Паспорт85;

Процедура ПриОткрытии()
    Если Инициализирован85 <> Неопределено Тогда
        ВызватьИсключение "Пульт не переинициализируется";
    КонецЕсли;
    Инициализирован85 = Ложь;
    Остановлен85 = Истина;
    Паспорт85 = УзлыИсточник85.Прочитать85();
    МаркерПульта85 = "6b0a5f95-cd23-4a6d-9e08-936170b5a4bd";
    Этап85 = 1;
    Инициализирован85 = Истина;
    Остановлен85 = Ложь;
    Статус85 = "Готово. В реальном списке выберите N85, D85, N85. После этого отдельно изучите черновик.";
КонецПроцедуры

Процедура ПроверитьПульт85() Экспорт
    Если Инициализирован85 <> Истина Или Остановлен85 Или МаркерПульта85 <> "6b0a5f95-cd23-4a6d-9e08-936170b5a4bd"
        Или ТипЗнч(Паспорт85) <> Тип("Структура") Или Паспорт85.Количество() <> 5 Тогда
        ВызватьИсключение "Нужен действительный подготовленный пульт известного этапа";
    КонецЕсли;
КонецПроцедуры

Функция ПолучитьПаспорт85() Экспорт
    Если Инициализирован85 <> Истина Или МаркерПульта85 <> "6b0a5f95-cd23-4a6d-9e08-936170b5a4bd"
        Или ТипЗнч(Паспорт85) <> Тип("Структура") Или Паспорт85.Количество() <> 5 Тогда
        ВызватьИсключение "Нет собственной фактической начальной структуры паспорта";
    КонецЕсли;
    Возврат Паспорт85;
КонецФункции

Процедура ПроверитьЧерновик85(Форма) Экспорт
    Если Инициализирован85 <> Истина Или Форма = Неопределено Или Форма <> СвойЧерновик85 Или Форма.ВладелецФормы <> ЭтаФорма Тогда
        ВызватьИсключение "Не совпали actual черновая форма и её единственный собственный владелец";
    КонецЕсли;
КонецПроцедуры

Процедура Выбрать85(Кнопка)
    Если Кнопка <> ЭлементыФормы.Выбрать85 Тогда
        ВызватьИсключение "Чужая кнопка выбора";
    КонецЕсли;
    ПроверитьПульт85();
    Если СвойСписок85 <> Неопределено И СвойСписок85.Открыта() Тогда
        ВызватьИсключение "Сначала вручную завершите/отмените действительный текущий выбор";
    КонецЕсли;
    СвойСписок85 = УзлыВыбор85.ПодготовитьСписок85(ЭтаФорма);
    СвойСписок85.Открыть();
КонецПроцедуры

Процедура ОбработкаВыбора(ЗначениеВыбора, Источник)
    ПроверитьПульт85();
    Если Источник = Неопределено Или Источник <> СвойСписок85 Или Источник.ВладелецФормы <> ЭтаФорма
        Или ТипЗнч(ЗначениеВыбора) <> Тип("ПланОбменаСсылка.Узлы85") Тогда
        ВызватьИсключение "Нужны actual источник собственного списка и единственный NodeRef, не массив";
    КонецЕсли;
    ЭлементыФормы.ВыборУзла85.Значение = ЗначениеВыбора;
    УзлыВыбор85.РассчитатьВыбор85(ЭтаФорма);
КонецПроцедуры

Процедура УзелПриИзменении85(Элемент)
    Если Элемент <> ЭлементыФормы.ВыборУзла85 Или Элемент.Имя <> "ВыборУзла85" Тогда
        ВызватьИсключение "Native OnChange поступает только от своего поля";
    КонецЕсли;
    УзлыВыбор85.РассчитатьВыбор85(ЭтаФорма);
КонецПроцедуры

Процедура Черновик85(Кнопка)
    Если Кнопка <> ЭлементыФормы.Черновик85 Тогда
        ВызватьИсключение "Чужая кнопка черновика";
    КонецЕсли;
    ПроверитьПульт85();
    Если Этап85 <> 4 Или СвойЧерновик85 <> Неопределено Тогда
        ВызватьИсключение "Нужен завершённый N/D/N и единственный новый черновик";
    КонецЕсли;
    УзлыИсточник85.ПроверитьСохранность85(Паспорт85);
    Исходный = Паспорт85.Обычный.ПолучитьОбъект();
    Если Исходный = Неопределено Или ТипЗнч(Исходный) <> Тип("ПланОбменаОбъект.Узлы85") Или Исходный.Ссылка <> Паспорт85.Обычный Тогда
        ВызватьИсключение "Не прочитан собственный N85";
    КонецЕсли;
    Копия = Исходный.Скопировать();
    Если ТипЗнч(Копия) <> Тип("ПланОбменаОбъект.Узлы85") Или Не Копия.ЭтоНовый() Тогда
        ВызватьИсключение "Native Copy должен вернуть actual новый несохранённый NodeObject";
    КонецЕсли;
    Ключ = Новый УникальныйИдентификатор;
    СвойЧерновик85 = Копия.ПолучитьФорму("Узел85", ЭтаФорма, Ключ);
    Если СвойЧерновик85 = Неопределено Или ТипЗнч(СвойЧерновик85) <> Тип("Форма") Или СвойЧерновик85.Открыта()
        Или СвойЧерновик85.ВладелецФормы <> ЭтаФорма Или СвойЧерновик85.КлючУникальности <> Ключ Или СвойЧерновик85.Узел85 <> Копия Тогда
        ВызватьИсключение "Native GetForm не вернул prepared форму именно этой копии";
    КонецЕсли;
    СвойЧерновик85.ПодготовитьЧерновик85();
    СвойЧерновик85.Открыть();
КонецПроцедуры
Полный запрет записи узла во всех native контекстах

ПланыОбмена → Узлы85 → Модуль объекта после manual fixture

Native BeforeWrite1; Server/thick/external; никаких client-only callee

Процедура ПередЗаписью(Отказ)
    Отказ = Истина;
КонецПроцедуры
Полный startup собственно подготовленного пульта

Конфигурация → Модуль обычного приложения, целиком

ПриНачалеРаботыСистемы0/обычное приложение

Процедура ПриНачалеРаботыСистемы()
    УзлыИсточник85.Прочитать85();
    Ключ = Новый УникальныйИдентификатор;
    Форма = Обработки.Пульт85.ПолучитьФорму("Пульт85", , Ключ);
    Если Форма = Неопределено Или ТипЗнч(Форма) <> Тип("Форма") Или Форма.Открыта() Или Форма.КлючУникальности <> Ключ Тогда
        ВызватьИсключение "Не получен actual новый собственный обычный пульт";
    КонецЕсли;
    Форма.Открыть();
КонецПроцедуры

Разбор по шагам

  1. Полный паспорт трёх своих узлов и actual currentRef; пустой НЕ-RIB план.

  2. Штатная фабрика списка, primary data/control/column/owner/type readback.

  3. Позиционирование до Open и genuine native Choice2 либо OnChange1.

  4. Actual selectedObject coefficient × конкретная собственная память; fresh полный source/версии/даты после расчёта.

Как проверить результат

  1. Cancel не вычисляет и не продвигает этап.

  2. ЭтотУзел/массив/чужой ref/неожиданный коэффициент не подставляются.

  3. 1000/500/1000 являются локальной арифметикой, не свидетельством обмена.

Ожидаемый результат

N85(1) → 1000; D85(0.5) → 500; N85(1) → 1000. Все три сохранённых узла и их поля/версии/даты сохранены.

На что обратить внимание

  1. Текущая строка задаёт позиционирование при Open, не автоматический выбор.

  2. Свойство стандартной картинки не означает вручную назначенный рисунок и заменяет использование КартинкиСтрок.

  3. Чтение номера сообщений0 не доказывает состояние всех скрытых служебных хранилищ; программа не вызывает обмен/регистрацию.

  4. Нет заявленной атомарности или concurrent-proof по одному readback.

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

Не хотите разбираться сами?

Адаптируем это решение под вашу базу. Оценка бесплатно.

Оставить задачу

1С, 1С:Предприятие — товарные знаки ООО «1С». Сайт не является официальным представительством фирмы «1С» и не аффилирован с ней.