Как программно записать единицу измерения и цену в справочник в 1С 7.7

Программист 1С v7.7 Управленческий учет Торговля и дистрибуция
← На главную

Работа со справочниками в 1С:Предприятии версии 7.7 имеет ряд существенных отличий от более современных версий платформы. Одной из наиболее часто встречающихся задач является автоматизированная загрузка прайс-листов, где требуется программно создать или обновить записи в справочнике Цены. Сложность заключается в том, что в типовых конфигурациях (например, «Торговля и Склад») справочник Цены является подчиненным справочнику Номенклатура (или ТМЦ), а реквизиты «Цена» и «Единица» часто являются периодическими.

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

Разберем архитектуру данных

Прежде чем переходить к написанию кода, проанализируем структуру объектов. Справочник Цены обычно подчинен справочнику ТМЦ. Это значит, что каждый элемент цен «знает» своего владельца. Кроме того, единица измерения в 1С 7.7 — это не просто строковое значение или ссылка на классификатор, а чаще всего отдельный подчиненный справочник Единицы, где владельцем также выступает конкретная номенклатурная позиция.

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

  1. Нарушение последовательности записи: Нельзя установить значение периодического реквизита для элемента, который еще не был физически записан в базу данных (метод Записать()).
  2. Несоответствие типов: Попытка записать в реквизит «Единица» значение базовой единицы из карточки номенклатуры напрямую, тогда как система ожидает элемент справочника Единицы.
  3. Отсутствие владельца: При создании новой цены не установлен или неверно указан Владелец.
  4. Ошибки позиционирования: Объект справочника создан, но не выбран конкретный элемент для модификации.

Алгоритм правильной записи периодического реквизита

Выясним причину, по которой метод Установить() может не срабатывать. В 1С 7.7 для периодических реквизитов критически важно, чтобы у объекта уже был сформирован внутренний идентификатор. Рассмотрим по шагам правильный порядок действий при создании новой цены.

Сначала мы создаем объект и заполняем его основные (непериодические) реквизиты:


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

Только после вызова метода Записать() мы можем обращаться к периодическим реквизитам через метод Установить() или через объект Периодический.

Поиск корректной единицы измерения

Посмотрим на ситуацию со стороны справочника единиц. В 1С 7.7 для каждого товара существует свой набор единиц (шт., кг., коробка), которые хранятся в подчиненном справочнике. Если мы просто возьмем Ном.БазоваяЕдиница, мы можем получить ссылку на общий классификатор или на элемент, не связанный с конкретной ценой. Нам необходимо найти единицу, владельцем которой является наша номенклатура.

Проанализируем пример кода для поиска единицы измерения по наименованию с учетом владельца:


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

Использование объекта Периодический для надежности

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

Рассмотрим пример реализации:


ОбъектПер = СоздатьОбъект("Периодический");

// Устанавливаем цену
ОбъектПер.ИспользоватьОбъект("Цена", СпрЦены.ТекущийЭлемент());
ОбъектПер.ДатаЗнач = ДатаАктуальностиЦен;
ОбъектПер.Значение = Число(Таблица.Область(жж,уу).Текст);
ОбъектПер.Записать();

// Устанавливаем единицу измерения
ОбъектПер.ИспользоватьОбъект("Единица", СпрЦены.ТекущийЭлемент());
ОбъектПер.ДатаЗнач = ДатаАктуальностиЦен;
ОбъектПер.Значение = НужнаяЕдиница;
ОбъектПер.Записать();

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

Сведем все полученные знания в единый программный блок. Мы проанализируем входящие данные, найдем (или создадим) элемент справочника Цены и корректно заполним его исторические данные.


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

Важные замечания по типам данных

Обратите внимание на попытки использования метода ПолучитьОбъект(), которые встречаются в некоторых обсуждениях. В 1С 7.7 этого метода не существует. Это синтаксис платформы 1С 8.х. Если вы попытаетесь вызвать его в "семерке", система выдаст ошибку Поле агрегатного объекта не обнаружено (ПолучитьОбъект). В 7.7 работа всегда идет напрямую с объектом, созданным через СоздатьОбъект, и позиционированным методами Найти..., Выбрать... или Получить....

Также важно помнить про дату актуальности. Если вы записываете цену на 01.01.2023, а в справочнике или отчете смотрите данные на сегодня, убедитесь, что в истории реквизита нет более поздних записей, которые «перекрывают» вашу загрузку. Всегда проверяйте результат через кнопку «История» в карточке справочника Цены.

Подводя итог: для успешной записи единицы измерения в справочник цен в 1С 7.7 необходимо соблюдать строгую последовательность: позиционирование на владельце -> создание/поиск элемента цены -> физическая запись объекта -> установка периодических реквизитов с использованием корректно найденных ссылок на подчиненные справочники единиц.

← На главную