Цены и сумма: доступные значения, формат ввода, использование и локальные идентификаторы

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

Создаём настоящую собственную таблицу продаж, обычное поле цены и вычисляемое описание суммы. Проверяем список500/700 и его снятие; у обоих полей меняем формат редактирования и отдельно использование. Поиск, доступные параметры, принадлежность записи и локальный идентификатор проверяются на действующих объектах, независимая копия остаётся исходной.

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

Полный серверный общий модуль УчебныеЗадачи новой пустой конфигурации УчебноеРедактирование85; в1С не запускался.

Подготовка

  1. Только НОВАЯ отдельная пустая база УчебноеРедактирование85 на точной платформе8.5.1.1343, не копия рабочей. Нет бизнес-объектов, расширений, подписок и фоновых заданий. Здесь база не создаётся и код не запускается.

  2. Вручную создайте общий модуль УчебныеЗадачи: Сервер=Да, Вызов сервера=Да; клиентские флаги, Глобальный и Привилегированный=Нет. Весь основной модуль вставьте целиком, не внутрь другой процедуры.

  3. Своя внешняя обработка УчебноеРедактирование85 → управляемая Форма: команда Выполнить, действие Выполнить и кнопка. Полный отдельный модуль формы ниже предназначен только для этого модуля формы. Перед будущим разрешённым опытом сохраните свою базу, выполните F7 вне опыта и откройте свежий сеанс без расширений.

  4. Сам код создаёт A01/3/500 и B02/5/700, Local-источник, объектный набор Продажи85 и соответствующий внешний ключ. Код85 — Строка; Количество85 — Число(1,0), Цена85 — Число(3,0), сумма — Число(6,2), всё числовое неотрицательное. Шесть разрядов ВСЕГО включают два дробных, предел9999.99. У исходных цен дробная часть0 сохраняется при любом формате.

  5. Обычное поле Цена85 и вычисляемое Сумма85 реально принадлежат собственной схеме. У них читается readonly ПараметрыРедактирования; штатный ФорматРедактирования ищется через ДоступныеПараметры.НайтиПараметр с настоящим ПараметрКомпоновкиДанных. Не создаются произвольные параметры, подмена контейнера или неизвестные записи.

Процедура ВыполнитьПример() Экспорт
    ПроверитьСвойПустойСтенд();
    Если ПривилегированныйРежим() Тогда
        ВызватьИсключение "Привилегированный режим не нужен";
    КонецЕсли;
    Стенд = СоздатьСвойСтендРедактирования();
    Цена = СвоеПолеРедактирования(Стенд, "Цена");
    ПроверитьСвоеРедактирование(Стенд, "Нет", "", "ЧДЦ=2", Истина, "ЧДЦ=2", Истина);
    Цена.УстановитьДоступныеЗначения(СоздатьСвоиЦеныВыбора(Стенд, "Все"));
    ПроверитьСвоеРедактирование(Стенд, "Все", "", "ЧДЦ=2", Истина, "ЧДЦ=2", Истина);
    Копия = СоздатьСвойСтендРедактирования();
    ЦенаКопии = СвоеПолеРедактирования(Копия, "Цена");
    ЦенаКопии.УстановитьДоступныеЗначения(СоздатьСвоиЦеныВыбора(Копия, "Все"));
    ПроверитьСвоеРедактирование(Копия, "Все", "", "ЧДЦ=2", Истина, "ЧДЦ=2", Истина);
    ПроверитьЧужиеЗаписиРедактирования(Стенд, Копия);
    Цена.ВыражениеПредставления = "Код85";
    ПроверитьСвоеРедактирование(Стенд, "Все", "Код85", "ЧДЦ=2", Истина, "ЧДЦ=2", Истина);
    Цена.УстановитьДоступныеЗначения(СоздатьСвоиЦеныВыбора(Стенд, "ТолькоB02"));
    ПроверитьСвоеРедактирование(Стенд, "ТолькоB02", "Код85", "ЧДЦ=2", Истина, "ЧДЦ=2", Истина);
    ПроверитьСвоеРедактирование(Копия, "Все", "", "ЧДЦ=2", Истина, "ЧДЦ=2", Истина);
    УстановитьСвойФормат(Стенд, "Цена", "ЧДЦ=0");
    ПроверитьСвоеРедактирование(Стенд, "ТолькоB02", "Код85", "ЧДЦ=0", Истина, "ЧДЦ=2", Истина);
    ПроверитьСвоеРедактирование(Копия, "Все", "", "ЧДЦ=2", Истина, "ЧДЦ=2", Истина);
    ЗаписьЦены = СвояЗаписьФормата(СвойРедакторПоля(Стенд, "Цена"));
    ЗаписьЦены.Использование = Ложь;
    ПроверитьСвоеРедактирование(Стенд, "ТолькоB02", "Код85", "ЧДЦ=0", Ложь, "ЧДЦ=2", Истина);
    ПроверитьСвоеРедактирование(Копия, "Все", "", "ЧДЦ=2", Истина, "ЧДЦ=2", Истина);
    УстановитьСвойФормат(Стенд, "Цена", "ЧДЦ=0");
    ПроверитьСвоеРедактирование(Стенд, "ТолькоB02", "Код85", "ЧДЦ=0", Истина, "ЧДЦ=2", Истина);
    УстановитьСвойФормат(Стенд, "Сумма", "ЧДЦ=0");
    ПроверитьСвоеРедактирование(Стенд, "ТолькоB02", "Код85", "ЧДЦ=0", Истина, "ЧДЦ=0", Истина);
    ПроверитьСвоеРедактирование(Копия, "Все", "", "ЧДЦ=2", Истина, "ЧДЦ=2", Истина);
    Цена.УстановитьДоступныеЗначения();
    ПроверитьСвоеРедактирование(Стенд, "Нет", "Код85", "ЧДЦ=0", Истина, "ЧДЦ=0", Истина);
    ЗаписьСуммы = СвояЗаписьФормата(СвойРедакторПоля(Стенд, "Сумма"));
    ЗаписьСуммы.Использование = Ложь;
    ПроверитьСвоеРедактирование(Стенд, "Нет", "Код85", "ЧДЦ=0", Истина, "ЧДЦ=0", Ложь);
    ПроверитьСвоеРедактирование(Копия, "Все", "", "ЧДЦ=2", Истина, "ЧДЦ=2", Истина);
    УстановитьСвойФормат(Стенд, "Цена", "ЧДЦ=2");
    УстановитьСвойФормат(Стенд, "Сумма", "ЧДЦ=2");
    Цена.ВыражениеПредставления = "";
    ПроверитьСвоеРедактирование(Стенд, "Нет", "", "ЧДЦ=2", Истина, "ЧДЦ=2", Истина);
    Цена.УстановитьДоступныеЗначения(СоздатьСвоиЦеныВыбора(Стенд, "Все"));
    ПроверитьСвоеРедактирование(Стенд, "Все", "", "ЧДЦ=2", Истина, "ЧДЦ=2", Истина);
    ПроверитьСвоеРедактирование(Копия, "Все", "", "ЧДЦ=2", Истина, "ЧДЦ=2", Истина);
    ПроверитьЧужиеЗаписиРедактирования(Стенд, Копия);
КонецПроцедуры

Процедура ПроверитьСвойПустойСтенд()
    Если Метаданные.Справочники.Количество() <> 0 Или Метаданные.Документы.Количество() <> 0 Или Метаданные.Перечисления.Количество() <> 0 Или Метаданные.РегистрыСведений.Количество() <> 0 Или Метаданные.РегистрыНакопления.Количество() <> 0 Или Метаданные.РегистрыБухгалтерии.Количество() <> 0 Или Метаданные.РегистрыРасчета.Количество() <> 0 Или Метаданные.ПланыВидовХарактеристик.Количество() <> 0 Или Метаданные.ПланыВидовРасчета.Количество() <> 0 Или Метаданные.ПланыСчетов.Количество() <> 0 Или Метаданные.ПланыОбмена.Количество() <> 0 Или Метаданные.Последовательности.Количество() <> 0 Или Метаданные.БизнесПроцессы.Количество() <> 0 Или Метаданные.Задачи.Количество() <> 0 Или Метаданные.ОбщиеРеквизиты.Количество() <> 0 Или Метаданные.ПодпискиНаСобытия.Количество() <> 0 Или Метаданные.РегламентныеЗадания.Количество() <> 0 Или Метаданные.ВнешниеИсточникиДанных.Количество() <> 0 Тогда
        ВызватьИсключение "Нужен только свой новый пустой учебный стенд";
    КонецЕсли;
    Если Метаданные.ЕстьИзмененияРасширениямиКонфигурации() Тогда
        ВызватьИсключение "Свой сеанс не должен изменяться расширениями";
    КонецЕсли;
    Источники = Новый Массив;
    Источники.Добавить(ИсточникРасширенийКонфигурации.БазаДанных);
    Источники.Добавить(ИсточникРасширенийКонфигурации.СеансАктивные);
    Источники.Добавить(ИсточникРасширенийКонфигурации.СеансОтключенные);
    Для Каждого Источник Из Источники Цикл
        Расширения = РасширенияКонфигурации.Получить(, Источник);
        Если ТипЗнч(Расширения) <> Тип("Массив") Тогда
            ВызватьИсключение "Native список расширений должен иметь тип Массив";
        КонецЕсли;
        Если Расширения.Количество() <> 0 Тогда
            ВызватьИсключение "В своём новом стенде нет расширений базы или сеанса";
        КонецЕсли;
    КонецЦикла;
    Если ТранзакцияАктивна() Тогда
        ВызватьИсключение "Чужая или вложенная активная транзакция не допускается";
    КонецЕсли;
КонецПроцедуры

Функция СвояРазрядностьПродаж(Имя)
    Если Имя = "Код85" Тогда
        Возврат 0;
    ИначеЕсли Имя = "Количество85" Тогда
        Возврат 1;
    ИначеЕсли Имя = "Цена85" Тогда
        Возврат 3;
    ИначеЕсли Имя = "Сумма85" Тогда
        Возврат 6;
    КонецЕсли;
    ВызватьИсключение "В своей модели продаж только четыре заранее определённых поля";
КонецФункции

Функция СвойТипПродаж(Имя)
    Разрядность = СвояРазрядностьПродаж(Имя);
    Если Разрядность = 0 Тогда
        Возврат Новый ОписаниеТипов("Строка");
    КонецЕсли;
    ДробнаяЧасть = 0;
    Если Разрядность = 6 Тогда
        ДробнаяЧасть = 2;
    КонецЕсли;
    Возврат Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(Разрядность, ДробнаяЧасть, ДопустимыйЗнак.Неотрицательный));
КонецФункции

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

Функция СоздатьСвоюОсновуПродаж()
    Данные = Новый ТаблицаЗначений;
    Имена = СтрРазделить("Код85,Количество85,Цена85", ",");
    Для Каждого Имя Из Имена Цикл
        Данные.Колонки.Добавить(Имя, СвойТипПродаж(Имя));
    КонецЦикла;
    СтрокаПродажи = Данные.Добавить();
    СтрокаПродажи.Код85 = "A01";
    СтрокаПродажи.Количество85 = 3;
    СтрокаПродажи.Цена85 = 500;
    СтрокаПродажи = Данные.Добавить();
    СтрокаПродажи.Код85 = "B02";
    СтрокаПродажи.Количество85 = 5;
    СтрокаПродажи.Цена85 = 700;
    Схема = Новый СхемаКомпоновкиДанных;
    Источник = Схема.ИсточникиДанных.Добавить();
    Источник.Имя = "СвоиПродажи85";
    Источник.ТипИсточникаДанных = "Local";
    Набор = Схема.НаборыДанных.Добавить(Тип("НаборДанныхОбъектСхемыКомпоновкиДанных"));
    Если ТипЗнч(Набор) <> Тип("НаборДанныхОбъектСхемыКомпоновкиДанных") Тогда
        ВызватьИсключение "Нужен собственный объектный набор продаж";
    КонецЕсли;
    Набор.Имя = "Продажи85";
    Набор.ИмяОбъекта = "Продажи85";
    Набор.ИсточникДанных = "СвоиПродажи85";
    Для Каждого Имя Из Имена Цикл
        Поле = Набор.Поля.Добавить(Тип("ПолеНабораДанныхСхемыКомпоновкиДанных"));
        Если ТипЗнч(Поле) <> Тип("ПолеНабораДанныхСхемыКомпоновкиДанных") Тогда
            ВызватьИсключение "Нужно собственное простое поле исходных продаж";
        КонецЕсли;
        Поле.Поле = Имя;
        Поле.ПутьКДанным = Имя;
        Поле.ТипЗначения = СвойТипПродаж(Имя);
    КонецЦикла;
    ВнешниеДанные = Новый Структура;
    ВнешниеДанные.Вставить("Продажи85", Данные);
    Стенд = Новый Структура;
    Стенд.Вставить("Схема", Схема);
    Стенд.Вставить("ВнешниеДанные", ВнешниеДанные);
    Возврат Стенд;
КонецФункции

Процедура ПроверитьСвоюОсновуПродаж(Стенд)
    Если ТипЗнч(Стенд) <> Тип("Структура") Или Стенд.Количество() <> 2 Тогда
        ВызватьИсключение "Нужна собственная структура схемы и внешних продаж";
    КонецЕсли;
    Схема = Неопределено;
    ВнешниеДанные = Неопределено;
    Если Не Стенд.Свойство("Схема", Схема) Или Не Стенд.Свойство("ВнешниеДанные", ВнешниеДанные) Тогда
        ВызватьИсключение "Не совпали оба собственных ключа стенда продаж";
    КонецЕсли;
    Если ТипЗнч(Схема) <> Тип("СхемаКомпоновкиДанных") Или Схема.ИсточникиДанных.Количество() <> 1
        Или Схема.НаборыДанных.Количество() <> 1 Тогда
        ВызватьИсключение "Нужен единственный собственный источник и объектный набор";
    КонецЕсли;
    Если ТипЗнч(ВнешниеДанные) <> Тип("Структура") Или ВнешниеДанные.Количество() <> 1 Тогда
        ВызватьИсключение "Нужен единственный собственный внешний объект продаж";
    КонецЕсли;
    Данные = Неопределено;
    Если Не ВнешниеДанные.Свойство("Продажи85", Данные) Тогда
        ВызватьИсключение "Внешний ключ обязан содержать настоящую собственную таблицу";
    КонецЕсли;
    Если ТипЗнч(Данные) <> Тип("ТаблицаЗначений") Или Данные.Количество() <> 2 Или Данные.Колонки.Количество() <> 3 Тогда
        ВызватьИсключение "Нужны две собственные продажи и три колонки";
    КонецЕсли;
    Источник = Схема.ИсточникиДанных.Получить(0);
    Если ТипЗнч(Источник) <> Тип("ИсточникДанныхСхемыКомпоновкиДанных")
        Или Источник.Имя <> "СвоиПродажи85" Или Источник.ТипИсточникаДанных <> "Local" Тогда
        ВызватьИсключение "Не совпал собственный логический источник";
    КонецЕсли;
    Набор = Схема.НаборыДанных.Получить(0);
    Если ТипЗнч(Набор) <> Тип("НаборДанныхОбъектСхемыКомпоновкиДанных") Или Набор.Имя <> "Продажи85"
        Или Набор.ИмяОбъекта <> "Продажи85" Или Набор.ИсточникДанных <> "СвоиПродажи85"
        Или Схема.НаборыДанных.Найти("Продажи85") <> Набор Или Набор.Поля.Количество() <> 3 Тогда
        ВызватьИсключение "Не совпал полный собственный набор и его три исходных поля";
    КонецЕсли;
    Имена = СтрРазделить("Код85,Количество85,Цена85", ",");
    Для Индекс = 0 По 2 Цикл
        Колонка = Данные.Колонки.Получить(Индекс);
        Поле = Набор.Поля.Получить(Индекс);
        Если ТипЗнч(Колонка) <> Тип("КолонкаТаблицыЗначений") Или Колонка.Имя <> Имена[Индекс]
            Или ТипЗнч(Поле) <> Тип("ПолеНабораДанныхСхемыКомпоновкиДанных")
            Или Поле.Поле <> Имена[Индекс] Или Поле.ПутьКДанным <> Имена[Индекс] Тогда
            ВызватьИсключение "Не совпали все имена, порядок и пути исходных колонок и полей";
        КонецЕсли;
        ПроверитьСвойТипПродаж(Колонка.ТипЗначения, Имена[Индекс]);
        ПроверитьСвойТипПродаж(Поле.ТипЗначения, Имена[Индекс]);
    КонецЦикла;
    Коды = СтрРазделить("A01,B02", ",");
    Количества = Новый Массив;
    Количества.Добавить(3);
    Количества.Добавить(5);
    Цены = Новый Массив;
    Цены.Добавить(500);
    Цены.Добавить(700);
    Суммы = Новый Массив;
    Суммы.Добавить(1500);
    Суммы.Добавить(3500);
    Для Индекс = 0 По 1 Цикл
        СтрокаПродажи = Данные.Получить(Индекс);
        Если ТипЗнч(СтрокаПродажи) <> Тип("СтрокаТаблицыЗначений")
            Или ТипЗнч(СтрокаПродажи.Код85) <> Тип("Строка") Или СтрокаПродажи.Код85 <> Коды[Индекс]
            Или ТипЗнч(СтрокаПродажи.Количество85) <> Тип("Число") Или СтрокаПродажи.Количество85 <> Количества[Индекс]
            Или ТипЗнч(СтрокаПродажи.Цена85) <> Тип("Число") Или СтрокаПродажи.Цена85 <> Цены[Индекс]
            Или СтрокаПродажи.Количество85 * СтрокаПродажи.Цена85 <> Суммы[Индекс] Тогда
            ВызватьИсключение "Не совпали все собственные ячейки и отдельный арифметический эталон BSL";
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Процедура ПроверитьСвойСписокЦен(Список, Эталон)
    Если ТипЗнч(Список) <> Тип("СписокЗначений") Или ТипЗнч(Эталон) <> Тип("СписокЗначений") Тогда
        ВызватьИсключение "Нужны настоящие собственные списки значений";
    КонецЕсли;
    Если Список.Количество() <> Эталон.Количество() Тогда
        ВызватьИсключение "Не совпало полное количество доступных цен";
    КонецЕсли;
    Для Индекс = 0 По Эталон.Количество() - 1 Цикл
        Элемент = Список.Получить(Индекс);
        Ожидаемый = Эталон.Получить(Индекс);
        Если ТипЗнч(Элемент) <> Тип("ЭлементСпискаЗначений") Или ТипЗнч(Ожидаемый) <> Тип("ЭлементСпискаЗначений") Тогда
            ВызватьИсключение "Нужно читать элементы списка, не непосредственно их значения";
        КонецЕсли;
        Если ТипЗнч(Элемент.Значение) <> Тип("Число") Или Элемент.Значение <> Ожидаемый.Значение
            Или ТипЗнч(Элемент.Представление) <> Тип("Строка") Или Элемент.Представление <> Ожидаемый.Представление
            Или ТипЗнч(Элемент.Пометка) <> Тип("Булево") Или Элемент.Пометка <> Ожидаемый.Пометка Тогда
            ВызватьИсключение "Не совпали все цены, строковые подписи, пометки и порядок списка";
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

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

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

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

Функция СвояЗаписьФормата(Редактор)
    Параметр = СвойДоступныйПараметрФормата(Редактор);
    Запись = Редактор.НайтиЗначениеПараметра(Параметр);
    Если ТипЗнч(Запись) <> Тип("ЗначениеПараметраКомпоновкиДанных") Тогда
        ВызватьИсключение "После своей установки нужна настоящая запись значения формата";
    КонецЕсли;
    Возврат Запись;
КонецФункции

Процедура УстановитьСвойФормат(Стенд, Владелец, Формат)
    Если Формат <> "ЧДЦ=2" И Формат <> "ЧДЦ=0" Тогда
        ВызватьИсключение "В своём опыте только два документированных числовых формата";
    КонецЕсли;
    Редактор = СвойРедакторПоля(Стенд, Владелец);
    Параметр = СвойДоступныйПараметрФормата(Редактор);
    Редактор.УстановитьЗначениеПараметра(Параметр, Формат);
КонецПроцедуры

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

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

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

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

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

Своя внешняя обработка УчебноеРедактирование85 → управляемая Форма → Модуль

Полный отдельный модуль собственной формы с серверным вызовом; здесь не запускался.

&НаКлиенте
Процедура Выполнить(Команда)
    ВыполнитьНаСервере();
    Сообщить("Свои цены, два параметра формата, использование и локальные идентификаторы проверены; отчёт не выполнялся");
КонецПроцедуры

&НаСервереБезКонтекста
Процедура ВыполнитьНаСервере()
    УчебныеЗадачи.ВыполнитьПример();
КонецПроцедуры

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

  1. Список доступных цен строится из настоящих исходных ячеек500/700, с подписями «A01 — цена», «B02 — цена» и пометками Ложь. ТолькоB02 создаёт новый список700. Getter проверяется по всем значениям, типам, подписям, пометкам и порядку. Исходные две строки не фильтруются и не изменяются.

  2. Снятие списка — УстановитьДоступныеЗначения() без аргумента, после чего ожидается Неопределено. Пустой список и явно переданный Неопределено не подставляются по аналогии. Getter-список только читается, общая ссылка или глубокая копия не предполагаются.

  3. ВыражениеПредставления исходной цены меняется на настоящее поле Код85, затем возвращается пустая строка. Это отдельная строка описания, не подпись элемента списка и не формат ввода. Для обычного поля справка описывает переопределение стандартного представления; точное поведение пустой строки не переносится из контракта вычисляемого поля.

  4. ПараметрыРедактирования содержит штатные значения. СвойДоступныйПараметрФормата использует НайтиПараметр, проверяет найденный дескриптор и поддержку Строка его ОписаниеТипов. Перебор с сравнением имён дескрипторов не используется: параметры могут иметь многоязыковые синонимы.

  5. ЧДЦ=2 и ЧДЦ=0 — документированное число десятичных разрядов дробной части. УстановитьЗначениеПараметра принимает найденный ПараметрКомпоновкиДанных и строку; установка включает Использование. Формат не меняет ТипЗначения цены/суммы и не гарантирует принятие дробного ввода. Штатные остальные параметры не очищаются.

  6. НайтиЗначениеПараметра принимает ПараметрКомпоновкиДанных, не строку по аналогии с setter. Возвращённая настоящая запись сверяется с коллекцией Элементы через Индекс, Получить, оба числовых [] и границы. Затем свой GetIDByObject/GetObjectByID должен пройти круг до той же текущей записи.

  7. После каждой установки запись и локальный идентификатор получаются заново. Их сохранение при setter не заявляется. Отдельно выключаем Использование при неизменном ЧДЦ=0, затем повторная установка той же строки должна включить его снова. Старая запись после установки больше не используется.

  8. Двенадцать состояний оригинала проверяют списки/представление и оба формата с флагами: исходное снятие; все цены; представление Код85; толькоB02; формат цены0; отключение цены; повторное включение; формат суммы0; снятие списка; отключение суммы; восстановление обоих форматов/представления; полный исходный список.

  9. Семь сверок независимой модели сохраняют все цены, пустое представление, оба ЧДЦ=2 и использование Истина при изменениях оригинала. В начале и конце чужая настоящая запись копии не должна получать идентификатор у оригинала и наоборот. Чужие идентификаторы для поиска не передаются: глобальная уникальность и невозможность совпадений между владельцами не предполагаются.

  10. Настоящий КА2 КомпоновкаДанныхСервер переносит доступные значения обычного поля после проверки Неопределено. ОбщегоНазначенияУТКлиентСервер ищет запись параметров редактирования через Новый ПараметрКомпоновкиДанных и включает Использование. Эти процедуры и их рабочие поля не вызываются; точный собственный ФорматРедактирования подтверждён установленной справкой, не запуском КА2.

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

  1. Ожидаемый будущий итог: обе исходные продажи неизменны, единственная сумма сохраняет Количество85 * Цена85 и числовые квалификаторы; обычная цена снова имеет500/700 с прежними подписями/Ложь, представление пустое. У обоих редакторов ФорматРедактирования=ЧДЦ=2, Использование=Истина; собственные локальные идентификаторы возвращают действующие записи.

  2. Будущий отрицательный контроль только в отдельно разрешённом стенде: выключить Использование, оставив прежнее ожидание Истина, — проверка должна отказать при той же строке формата и тех же данных. Другие контроли: цена списка701 вместо700, неправильная подпись или запись другого контейнера для локального GetIDByObject. Здесь контроли не запускались.

  3. runtimeVerifiedScenarios=0. Подтверждены установленные типы/сигнатуры/контексты и статическая целостность. Не подтверждены реальные getter/setter/идентификаторы платформы, принятие ввода, маска/формат формы, отображение списка или результат СКД. Арифметический эталон1500/3500 не выдаётся за исполнение движка.

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

Полный собственный опыт модели цены и суммы: выбор, представление, формат и использование разделены; действующие записи и их локальная принадлежность проверены без общих данных.

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

  1. Не заменяйте readonly ПараметрыРедактирования, ДоступныеПараметры, Элементы или тип доступного дескриптора. Не присваивайте Параметр связанной записи: это может вызвать исключение. Редактируется документированный формат и отдельно Использование, остальные штатные значения сохраняются.

  2. Не путайте число дробных знаков формата с КвалификаторыЧисла.РазрядностьДробнойЧасти: цена остаётся собственным целым числом с тремя разрядами, сумма имеет шесть разрядов всего и два дробных. Формат редактирования не делает целое поле дробным и не является правилами финансового округления.

  3. Не держите прежнюю запись/идентификатор через УстановитьЗначениеПараметра и не используйте идентификатор другого редактора как переносимый ключ. Круг ID выполняется внутри своего действующего владельца; чужое членство проверяется по объекту, не по совпадению идентификаторов.

  4. Доступные цены не являются правами доступа, проверкой документа или автоматически установленным отбором. Возвращаемые записи/списки используются только в собственной модели, без предположений о внешнем интерфейсе.

  5. Не создаются настройки выбора, отбор, ресурсы, компоновщик макета или процессор; опыт не является исполнимым отчётом. Нет запуска1С, записи, запросов к рабочим данным, сети или печати. ДоступныеПоляПараметров и ограничения вычисляемого поля остаются отдельными темами, не привязываются ради одной проверки типа.

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

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

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

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

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