Как создать несколько дочерних документов на основании одной строки табличной части родительского документа в 1С?

Программист 1С v8.3 (Управляемые формы) 1С:ERP Управление предприятием Управленческий учет Торговля и дистрибуция
← На главную

При работе в системе 1С мы часто сталкиваемся с необходимостью создания новых документов на основании уже существующих. Стандартный механизм «Ввод на основании» отлично справляется с ситуациями, когда один документ-основание порождает один или несколько дочерних документов в целом. Однако что делать, если нам нужно создать отдельные «детки» для каждой конкретной строки табличной части «родителя»? Например, у нас есть документ «Поступление товаров» с множеством позиций в табличной части, и для каждой отдельной позиции (товара, партии) нам необходимо создать документ «Проверка качества ОКК», причем этот документ «Проверка качества» содержит всего один товар, и проверки могут происходить в разное время.

Стандартный механизм ввода на основании, как правило, ориентирован на документ в целом. Передача данных из конкретной строки табличной части в несколько отдельных дочерних документов требует особого подхода. Давайте рассмотрим несколько эффективных способов решения этой задачи, включая программное создание документов, использование уникальных идентификаторов строк и применение регистров накопления для контроля остатков.

Подход 1: Создание отдельной кнопки и программное заполнение документа

Первый и наиболее гибкий способ — это создание на форме документа «Поступление товаров» отдельной команды (кнопки), которая будет выполнять программное создание и заполнение документа «Проверка качества ОКК» на основании текущей выделенной строки табличной части. Этот метод позволяет нам полностью контролировать процесс передачи данных и связывания документов.

  1. Почему стандартный «Ввод на основании» не всегда подходит

    Механизм «Ввод на основании», настраиваемый через конфигуратор (с использованием процедуры ОбработкаЗаполнения()), идеально подходит для создания нового документа из всего документа-основания. Однако, если нам нужно создать много отдельных дочерних документов, каждый из которых ссылается на конкретную строку табличной части родительского документа, то стандартный механизм становится менее удобным. Он не предоставляет прямого способа выбора отдельной строки для создания одного дочернего документа.

  2. Создание команды и кнопки на форме

    Начнем с добавления новой команды на форму документа «Поступление товаров». Мы можем разместить ее в командной панели табличной части или в любом другом удобном месте.

    1. Откроем форму документа «Поступление товаров» в конфигураторе.
    2. В дереве элементов формы найдем раздел «Команды» и создадим новую команду, например, «СоздатьПроверкуКачества».
    3. В обработчике команды на клиенте вызовем серверную процедуру, передав ей текущую строку табличной части или ссылку на документ и идентификатор строки.
    4. Разместим кнопку на форме, привязав ее к созданной команде.
  3. Программное создание и заполнение документа «Проверка качества ОКК»

    В серверной процедуре обработки команды мы будем выполнять следующие шаги:

    1. Получение текущей строки табличной части: Предположим, что кнопка расположена рядом с табличной частью и мы можем получить текущую строку, на которой находится курсор.
      
      &НаКлиенте
      Процедура СоздатьПроверкуКачества(Команда)
          Если Элементы.СписокТоваров.ТекущиеДанные <> Неопределено Тогда
              ТекущаяСтрока = Элементы.СписокТоваров.ТекущиеДанные;
              СоздатьПроверкуКачестваНаСервере(Объект.Ссылка, ТекущаяСтрока.НомерСтроки, ТекущаяСтрока.ИдентификаторСтроки); // Передаем ссылку на документ и уникальный идентификатор строки
          Иначе
              Предупреждение("Не выбрана строка табличной части для создания документа проверки качества.");
          КонецЕсли;
      КонецПроцедуры
      
      &НаСервере
      Процедура СоздатьПроверкуКачестваНаСервере(СсылкаДокументаОснования, НомерСтрокиОснования, ИдентификаторСтрокиОснования)
          // ... дальнейшая логика ...
      КонецПроцедуры
      
    2. Создание нового документа: Используем менеджер документов для создания нового экземпляра.
      
      // ... внутри СоздатьПроверкуКачестваНаСервере
      НовыйДокумент = Документы.ПроверкаКачества.СоздатьДокумент();
      
    3. Заполнение реквизитов: Здесь мы передаем данные из строки поступления в новый документ.

      Мы заполняем основные реквизиты, такие как товар, количество, контрагент, а также ссылку на документ-основание и уникальный идентификатор строки для связи.

      
      // ... внутри СоздатьПроверкуКачестваНаСервере
      
      // Получаем данные из строки поступления
      Запрос = Новый Запрос;
      Запрос.Текст = 
      "ВЫБРАТЬ
      |    ПоступлениеТоваров.Номенклатура,
      |    ПоступлениеТоваров.Количество,
      |    ПоступлениеТоваров.ЕдиницаИзмерения,
      |    ПоступлениеТоваров.Партия,
      |    ПоступлениеТоваров.Контрагент
      |ИЗ
      |    Документ.ПоступлениеТоваров.Товары КАК ПоступлениеТоваров
      |ГДЕ
      |    ПоступлениеТоваров.Ссылка = &СсылкаДокументаОснования
      |    И ПоступлениеТоваров.ИдентификаторСтроки = &ИдентификаторСтрокиОснования"; // Используем уникальный идентификатор
                      
      Запрос.УстановитьПараметр("СсылкаДокументаОснования", СсылкаДокументаОснования);
      Запрос.УстановитьПараметр("ИдентификаторСтрокиОснования", ИдентификаторСтрокиОснования);
      
      РезультатЗапроса = Запрос.Выполнить();
      Если РезультатЗапроса.Пустой() Тогда
          Возврат; // Строка не найдена
      КонецЕсли;
                      
      Выборка = РезультатЗапроса.Выбрать();
      Выборка.Следующий();
      
      НовыйДокумент.Дата = ТекущаяДата();
      НовыйДокумент.Организация = СсылкаДокументаОснования.Организация;
      НовыйДокумент.Контрагент = Выборка.Контрагент;
      НовыйДокумент.Товар = Выборка.Номенклатура;
      НовыйДокумент.Количество = Выборка.Количество;
      НовыйДокумент.Партия = Выборка.Партия; // Если партия - отдельный справочник, то ссылка
      
      // Связываем документы
      НовыйДокумент.ДокументОснование = СсылкаДокументаОснования;
      НовыйДокумент.ИдентификаторСтрокиОснования = ИдентификаторСтрокиОснования; // Для точной привязки к строке
      
    4. Запись и открытие формы нового документа:
      
      // ... внутри СоздатьПроверкуКачестваНаСервере
                      
      Попытка
          НовыйДокумент.Записать(РежимЗаписиДокумента.Запись);
          Сообщить("Документ 'Проверка качества' №" + НовыйДокумент.Номер + " от " + НовыйДокумент.Дата + " успешно создан.");
      Исключение
          Сообщить("Ошибка при записи документа 'Проверка качества': " + ОписаниеОшибки());
          Возврат;
      КонецПопытки;
      
      // Открытие формы нового документа (клиентская часть)
      // Возвращаем ссылку, чтобы открыть на клиенте
      ОткрытьФормуДокументаПроверкаКачества(НовыйДокумент.Ссылка);
      
      
      &НаКлиенте
      Процедура ОткрытьФормуДокументаПроверкаКачества(СсылкаНаНовыйДокумент)
          Если ЗначениеЗаполнено(СсылкаНаНовыйДокумент) Тогда
              ОткрытьЗначение(СсылкаНаНовыйДокумент);
          КонецЕсли;
      КонецПроцедуры
      
  4. Важность уникального идентификатора строки

    Критически важно для надежной связи использовать уникальный идентификатор строки табличной части. Поле НомерСтроки ненадежно, так как оно может измениться при изменении порядка строк или удалении. Мы рекомендуем добавить в табличную часть «Товары» документа «Поступление товаров» новый реквизит, например, ИдентификаторСтроки типа УникальныйИдентификатор.

    Этот идентификатор следует заполнять при добавлении новой строки в табличную часть (например, в обработчике события ПриДобавленииСтроки() для табличной части формы, или в ОбработкаЗаполнения() для строк, добавляемых из других документов):

    
    &НаСервере
    Процедура ТоварыПриДобавленииСтроки(Элемент)
        Если Элемент.ТекущиеДанные.ИдентификаторСтроки = Неопределено Тогда
            Элемент.ТекущиеДанные.ИдентификаторСтроки = Новый УникальныйИдентификатор();
        КонецЕсли;
    КонецПроцедуры
    

    В документе «Проверка качества ОКК» также должен быть реквизит, например, ИдентификаторСтрокиОснования типа УникальныйИдентификатор, который будет хранить значение этого идентификатора из родительского документа.

Подход 2: Обратная связь – реквизит в табличной части родителя

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

  1. Добавление реквизита в табличную часть родителя

    Мы можем добавить в табличную часть «Товары» документа «Поступление товаров» новый реквизит, например, СсылкаНаПроверкуКачества типа ДокументСсылка.ПроверкаКачества. Этот реквизит будет хранить ссылку на созданный документ «Проверка качества ОКК», который был сделан по данной строке.

  2. Механизм работы

    При создании документа «Проверка качества ОКК» (например, по первому подходу с кнопкой), после его успешной записи, мы программно записываем ссылку на этот новый документ в соответствующий реквизит строки табличной части документа «Поступление товаров»:

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

    Главное ограничение: этот подход не работает, если по одной строке поступления может быть создано несколько документов «Проверка качества ОКК». Если же связь строго «один к одному», он обеспечивает быструю навигацию от строки поступления к связанному документу.

Подход 3: Использование регистра накопления для отслеживания состояния

Для более комплексного учета и отслеживания состояния товаров, требующих проверки качества, особенно если количество проверок может быть произвольным, наиболее надежным и масштабируемым решением будет использование регистра накопления. Этот подход позволяет нам вести учет "остатков" товаров, ожидающих проверку, и контролировать их движение.

  1. Создание регистра накопления

    Мы создадим новый регистр накопления с типом «Остатки», который будет хранить информацию о количестве товаров, подлежащих проверке. Назовем его, например, «ТоварыКПроверкеОКК».

    Измерения регистра:

    • Номенклатура (Тип: СправочникСсылка.Номенклатура) — для идентификации конкретного товара.
    • Партия (Тип: Строка или СправочникСсылка.СерииНоменклатуры, если используются серии) — критически важно для уникальной идентификации, если один и тот же товар может приходить с разными характеристиками или в разных партиях, как было отмечено в обсуждении.
    • ДокументПоступления (Тип: ДокументСсылка.ПоступлениеТоваров) — ссылка на документ-основание.
    • ИдентификаторСтрокиПоступления (Тип: УникальныйИдентификатор) — ссылка на конкретную строку табличной части поступления (тот же идентификатор, что мы вводили в Подходе 1). Это обеспечивает максимальную детализацию и точность связи.

    Ресурсы регистра:

    • КоличествоКПроверке (Тип: Число, Точность: 3 или более) — количество товара, которое еще не прошло проверку.
  2. Движения по регистру

    Мы будем формировать движения по этому регистру при проведении документов:

    1. Документ «Поступление товаров» (Приход):

      При проведении документа «Поступление товаров» для каждой строки табличной части «Товары» мы делаем движение типа «Приход» в регистр «ТоварыКПроверкеОКК». Это означает, что данное количество товара поступило и ожидает проверку.

      
      // Пример кода в модуле объекта документа ПоступлениеТоваров, в процедуре ОбработкаПроведения
                      
      Движения.ТоварыКПроверкеОКК.Записывать = Истина;
      Для Каждого СтрокаТабличнойЧасти Из Товары Цикл
          Движение = Движения.ТоварыКПроверкеОКК.Добавить();
          Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
          Движение.Период = Дата;
          Движение.Номенклатура = СтрокаТабличнойЧасти.Номенклатура;
          Движение.Партия = СтрокаТабличнойЧасти.Партия; // Или СсылкаНаСерию
          Движение.ДокументПоступления = Ссылка;
          Движение.ИдентификаторСтрокиПоступления = СтрокаТабличнойЧасти.ИдентификаторСтроки;
          Движение.КоличествоКПроверке = СтрокаТабличнойЧасти.Количество;
      КонецЦикла;
      
    2. Документ «Проверка качества ОКК» (Расход):

      При проведении документа «Проверка качества ОКК» мы делаем движение типа «Расход» из регистра «ТоварыКПроверкеОКК». Это означает, что определенное количество товара прошло проверку.

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

      
      // Пример кода в модуле объекта документа ПроверкаКачества, в процедуре ОбработкаПроведения
                      
      // Проверка доступности остатков (пример)
      Запрос = Новый Запрос;
      Запрос.Текст = 
      "ВЫБРАТЬ
      |    ТоварыКПроверкеОККОстатки.КоличествоКПроверкеОстаток
      |ИЗ
      |    РегистрНакопления.ТоварыКПроверкеОКК.Остатки(
      |        &Дата,
      |        Номенклатура = &Номенклатура
      |            И Партия = &Партия
      |            И ДокументПоступления = &ДокументПоступления
      |            И ИдентификаторСтрокиПоступления = &ИдентификаторСтрокиПоступления) КАК ТоварыКПроверкеОККОстатки";
                      
      Запрос.УстановитьПараметр("Дата", Дата);
      Запрос.УстановитьПараметр("Номенклатура", Товар);
      Запрос.УстановитьПараметр("Партия", Партия); // Или СсылкаНаСерию
      Запрос.УстановитьПараметр("ДокументПоступления", ДокументОснование);
      Запрос.УстановитьПараметр("ИдентификаторСтрокиПоступления", ИдентификаторСтрокиОснования);
                      
      РезультатЗапроса = Запрос.Выполнить();
      Если РезультатЗапроса.Пустой() Тогда
          Отказ = Истина;
          Сообщить("Нет товаров для проверки по указанной партии и документу.");
          Возврат;
      КонецЕсли;
                      
      Выборка = РезультатЗапроса.Выбрать();
      Выборка.Следующий();
                      
      Если Выборка.КоличествоКПроверкеОстаток < Количество Тогда
          Отказ = Истина;
          Сообщить("Недостаточно товаров для проверки. Доступно: " + Выборка.КоличествоКПроверкеОстаток + ", требуется: " + Количество);
          Возврат;
      КонецЕсли;
                      
      // Формирование движения расхода
      Движения.ТоварыКПроверкеОКК.Записывать = Истина;
      Движение = Движения.ТоварыКПроверкеОКК.Добавить();
      Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
      Движение.Период = Дата;
      Движение.Номенклатура = Товар;
      Движение.Партия = Партия; // Или СсылкаНаСерию
      Движение.ДокументПоступления = ДокументОснование;
      Движение.ИдентификаторСтрокиПоступления = ИдентификаторСтрокиОснования;
      Движение.КоличествоКПроверке = Количество;
      
  3. Преимущества использования регистра накопления

    • Контроль остатков: Мы всегда можем получить актуальную информацию о том, сколько товара по каждой партии и документу поступления еще ожидает проверку.
    • Отчетность: На основе регистра легко строятся отчеты, показывающие состояние контроля качества, непроверенные товары и т.д.
    • Гибкость: По одной строке поступления может быть создано любое количество документов «Проверка качества», пока есть остаток в регистре.
    • Целостность данных: Регистр обеспечивает автоматическую проверку доступности количества при проведении документов.

Дополнительные соображения и советы

При реализации любого из этих подходов, мы должны учитывать несколько важных моментов:

  1. Уникальность идентификации товара: Как было упомянуто в обсуждении, если в одном поступлении могут быть несколько позиций одного и того же товара, но с разными характеристиками (например, ценой, свойствами или привязкой к разным партиям), нам критически важно использовать все эти разрезы (номенклатура, партия, характеристика) для уникальной идентификации. Поле Партия в документе «Поступление товаров» может быть как строкой (для простого текстового обозначения), так и ссылкой на отдельный справочник «Партии», что предпочтительнее для строгой аналитики.
  2. Обработка изменений родительского документа: Мы должны продумать, что произойдет, если строка в документе «Поступление товаров» будет изменена или удалена после того, как по ней уже были созданы документы «Проверка качества».
    • Изменение количества: Если количество в поступлении уменьшается, нам нужно убедиться, что это не приведет к отрицательному остатку по регистру (если используется) или конфликтам с уже созданными документами проверки.
    • Удаление строки: Если строка поступления удаляется, возможно, потребуется отменить проведение или удалить связанные документы «Проверка качества», либо сделать соответствующие корректирующие движения в регистре.

    Эти сценарии обычно обрабатываются в процедуре ОбработкаПроведения документа «Поступление товаров» или в отдельной обработке.

  3. Пользовательский интерфейс: Для удобства пользователей, мы можем реализовать дополнительные функции:
    • Возможность просмотра всех документов «Проверка качества», связанных с конкретной строкой поступления, прямо из формы документа «Поступление товаров» (например, через дополнительную кнопку или расширение формы).
    • Отчеты, показывающие состояние проверки по всем поступлениям.

Заключение

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

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

← На главную