8.х Перенос строк из одного документа в другой

Тема в разделе "Конфигурирование на платформе "1С:Предприятие 8"", создана пользователем solovev, 19 апр 2010.

  1. TopicStarter Overlay
    solovev
    Offline

    solovev

    Регистрация:
    12 дек 2009
    Сообщения:
    9
    Симпатии:
    0
    Баллы:
    1
    Добрый день.

    Задача примерно такого характера:

    Есть масса документов, в этих документах в табличных частях есть строки, (не все) которые необходимо перенести в другой документ(2)..

    Ну т.е. получается надо выбрать каждый документ, пробежаться по ТаблицеЗначений и дальше добавить аналогичную строку в тот документ(2), после чего удалить строку из документа приемника. Ну и проводка документа-приемника.

    С 8.1 почти не знаком, так что если толкнете в сторону нужной информации или названия процедур -- буду признателен.
  2. Доктор Руфус Бейли
    Offline

    Доктор Руфус Бейли Опытный в 1С

    Регистрация:
    7 апр 2010
    Сообщения:
    277
    Симпатии:
    0
    Баллы:
    26
    Было бы проще подсказать, если бы я мог знать, в какой части у вас "затык" (и в чём). Способов реализовать данную задачу множество. Например:

    (самый наглядный и простой, на мой взгляд, для пояснения - но отнюдь не лучший с точки зрения оптимальности)
    1. Получаем объект для обработки целевого документа, в который будем добавлять строки (отлично работает метода "ПолучитьОбъект()"
    2. Запросом выбираем ссылки на документы, из которых будем переносить строки.
    3. В цикле перебираем эти объекты: получаем объект из каждой ссылки и выполняем цикл "для каждого" по табличной части.
    4. В случае, если строка удовлетворяет условиям, добавляем строку в табличный документ. (Строка = ТабличнаяЧасть.Добавить())
    5. Удаляем строку из табличной части документа, с которым работаем. (метод табличной части "Удалить()")
    6. Проведение документа происходит через "Объект.Записать(<параметры записи>).

    В помощь рекоммендую синтаксис-помощник. Вам нужно искать темы "ДокументОбъект" и "ТабличнаяЧасть".

    И, конечно же, хотелось бы знать, насколько распространяется ваше "почти не знаком". Работали ли вы с 7.7, имели ли опыт программирования на любом языке (не обязательно 1С) и т. д. Так будет проще понять, насколько широко распространяются ваши знания.
  3. TopicStarter Overlay
    solovev
    Offline

    solovev

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

    Выборка строк из документа работает.
    При нажатии на Выполнить до Индекс выходит за пределы с сообщением
    "Ошибка при вызове метода контекста (Удалить) Значение индекса выходит за границы диапозона".

    Почему? Хоть убей -- не пойму..
  4. BabySG
    Offline

    BabySG Администраторы Команда форума Администратор

    Регистрация:
    10 июн 2007
    Сообщения:
    11.853
    Симпатии:
    12
    Баллы:
    29
    Удалять надо в обратном порядке. Классическая ошибка новичков :)
  5. TopicStarter Overlay
    solovev
    Offline

    solovev

    Регистрация:
    12 дек 2009
    Сообщения:
    9
    Симпатии:
    0
    Баллы:
    1
    Особенность 1С-ки?
    Не ожидал ошибки, ведь обращение к строке-то идет по индексу..

    Ну, а удалять, я так понимаю For-ом?
  6. shurikvz
    Offline

    shurikvz Модераторы Команда форума Модератор

    Регистрация:
    1 окт 2009
    Сообщения:
    8.409
    Симпатии:
    316
    Баллы:
    104
    Особенность любого языка, если идет обращение по индексу. Скажем у вас в массиве (т.е. у вас в табличной части) 3 строки, если вы обращаетесь к ним по индексу и начинаете удаление с 1-й строки, то у вас уже останется их 2, таким образом при обращении массив[3] - индекс окажется вне диапазона.

    Да, For-ом, почему бы и нет.
  7. shurikvz
    Offline

    shurikvz Модераторы Команда форума Модератор

    Регистрация:
    1 окт 2009
    Сообщения:
    8.409
    Симпатии:
    316
    Баллы:
    104
    Процедура "Процедура ОтборНажатие(Элемент)": РезДокумент = РезультирующийДокументПоле.ПолучитьОбъект(); - это там зачем?

    Код:
    Для каждого ИсхСтрока из ИсхДокументПоле.Комплектующие цикл
    
    - это работает? зачем тогда получаете ИсхДокумент = ИсхДокументПоле.ПолучитьОбъект();?
  8. TopicStarter Overlay
    solovev
    Offline

    solovev

    Регистрация:
    12 дек 2009
    Сообщения:
    9
    Симпатии:
    0
    Баллы:
    1
    Это полностью рабочий код, уже проверянно.

    а
    Код:
    ИсхДокумент = ИсхДокументПоле.ПолучитьОбъект();
    
    
    Потому что у меня сыпал ошибку при удалении строки методом ИсхДокументПоле.Комплектующие.Удалить();
  9. shurikvz
    Offline

    shurikvz Модераторы Команда форума Модератор

    Регистрация:
    1 окт 2009
    Сообщения:
    8.409
    Симпатии:
    316
    Баллы:
    104
    Честно говоря - у вас весь код не очень. ИсхДокументПоле - это у вас что, поле ввода?

    В "Функция НаличиеНаСкладах(Ссылка)":
    Код:
    Для Каждого Наличие из Рез Цикл
    Возврат(Наличие.КоличествоОстаток);
    КонецЦикла;
    
    
    Для чего цикл? Возврат из функции будет сразу же после первой итерации. В запросе также не установлен склад, и не помню какие там еще измерения регистра (если у вас типовая) - это правильно? (зависит от логики программы).

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

    Оформите все ваше дело одним запросом. В запрос передаете список документов, в запросе группируете по документам, отбираете нужные строки, потом в переборе результата запроса - формируете ваш конечный документ, из исходных документов убираете нужные строки. Все это дело поместите в транзакцию.
  10. TopicStarter Overlay
    solovev
    Offline

    solovev

    Регистрация:
    12 дек 2009
    Сообщения:
    9
    Симпатии:
    0
    Баллы:
    1
    ну так я и не притендую на суперкрутой код, на данном этапе для меня важно было получить рабочую обработку. Процесс оптимизации еще впереди :)
    К тому же до этого с 8кой плотно не общался, о чем я уже и писал. С 7.7 было дело.

    да

    Цикл, согласен. Убрал.
    В запросе склада нет, по той простой причине что он не нужен в данном случае. Конфиг типовой УТ.
    Зачем добавлять еще условия если есть довольно четкое и однозначное (ссылка на документ)?

    Согласен, это была отладочная информация для проверки, убрал.

    Вот здесь для меня не совсем понятны некоторые моменты.
    Логика работы такая:
    1. Из документа(1) берется табличная часть, выбираются нужные строки и помещаются в ТаблицуЗначений для контроля. (Отбор)
    2. После нажатия (Выполнить) вызывается процедура добавления строк во второй документ(2), удаления строк из документа(1) и записи получившихся документов.

    ну вот как-то так...
  11. shurikvz
    Offline

    shurikvz Модераторы Команда форума Модератор

    Регистрация:
    1 окт 2009
    Сообщения:
    8.409
    Симпатии:
    316
    Баллы:
    104
    Код:
    Процедура КнопкаВыполнитьНажатие(Кнопка)
    // Вставить содержимое обработчика.
    
    //{{КОНСТРУКТОР_ЗАПРОСА_С_ОБРАБОТКОЙ_РЕЗУЛЬТАТА
    // Данный фрагмент построен конструктором.
    // При повторном использовании конструктора, внесенные вручную изменения будут утеряны!!!
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
    "ВЫБРАТЬ
    |    КомплектацияНоменклатуры.Ссылка КАК Ссылка,
    |    КомплектацияНоменклатурыКомплектующие.НомерСтроки КАК НомерСтроки,
    |    КомплектацияНоменклатурыКомплектующие.ДоляСтоимости,
    |    КомплектацияНоменклатурыКомплектующие.ЕдиницаИзмерения,
    |    КомплектацияНоменклатурыКомплектующие.Количество,
    |    КомплектацияНоменклатурыКомплектующие.Коэффициент,
    |    КомплектацияНоменклатурыКомплектующие.Номенклатура КАК Номенклатура,
    |    КомплектацияНоменклатурыКомплектующие.СерияНоменклатуры
    |ИЗ
    |    Документ.КомплектацияНоменклатуры.Комплектующие КАК КомплектацияНоменклатурыКомплектующие
    |        ЛЕВОЕ СОЕДИНЕНИЕ Документ.КомплектацияНоменклатуры КАК КомплектацияНоменклатуры
    |        ПО КомплектацияНоменклатурыКомплектующие.Ссылка = КомплектацияНоменклатуры.Ссылка
    |        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыНаСкладахОстатки
    |        ПО КомплектацияНоменклатурыКомплектующие.Номенклатура = ТоварыНаСкладахОстатки.Номенклатура
    |            И КомплектацияНоменклатурыКомплектующие.СерияНоменклатуры = ТоварыНаСкладахОстатки.СерияНоменклатуры
    |ГДЕ
    |    КомплектацияНоменклатуры.Ссылка В(&Ссылка)
    |    И ТоварыНаСкладахОстатки.КоличествоОстаток > 0
    |    И КомплектацияНоменклатурыКомплектующие.ДоляСтоимости = 1
    |
    |УПОРЯДОЧИТЬ ПО
    |    НомерСтроки УБЫВ
    |ИТОГИ ПО
    |    Ссылка";
    
    Запрос.УстановитьПараметр("Ссылка", Ссылка);
    
    Результат = Запрос.Выполнить();
    
    ВыборкаСсылка = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
    
    Попытка
    НачатьТранзакцию();
    //Создаем новый документ
    НовыйДокумент = Документы.КомплектацияНоменклатуры.СоздатьДокумент();
    НовыйДокумент.Дата = ТекущаяДата();
    //И т.д. заполняем реквизиты нового док-та
    //---
    //
    
    Пока ВыборкаСсылка.Следующий() Цикл
    // Вставить обработку выборки ВыборкаСсылка
    ДокументОбъект = ВыборкаСсылка.Ссылка.ПолучитьОбъект();
    ДокументОбъект.Записать(РежимЗаписиДокумента.ОтменаПроведения);
    
    ВыборкаДетальныеЗаписи = ВыборкаСсылка.Выбрать();
    Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
    // Вставить обработку выборки ВыборкаДетальныеЗаписи
    НоваяСтрока = НовыйДокумент.Комплектующие.Добавить();
    НоваяСтрока.ДоляСтоимости = ВыборкаДетальныеЗаписи.ДоляСтоимости;
    НоваяСтрока.ЕдиницаИзмерения = ВыборкаДетальныеЗаписи.ЕдиницаИзмерения;
    //и т.д. все поля
    
    //Удаляем из исходного док-та строку
    ДокументОбъект.Комплектующие.Удалить(ВыборкаДетальныеЗаписи.НомерСтроки);
    КонецЦикла;
    
    //Записываем исходный документ с изменениями
    ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение, РежимПроведенияДокумента.Неоперативный);
    КонецЦикла;
    
    //Попытка провести итоговый документ
    НовыйДокумент.Записать(РежимЗаписиДокумента.Проведение, РежимПроведенияДокумента.Неоперативный);
    ЗафиксироватьТранзакцию();
    
    Исключение
    ОбщегоНазначения.СообщитьОбОшибке("Не удалось провести документ: "+ОписаниеОшибки());
    ОтменитьТранзакцию();
    КонецПопытки;
    
    //}}КОНСТРУКТОР_ЗАПРОСА_С_ОБРАБОТКОЙ_РЕЗУЛЬТАТА
    
    КонецПроцедуры
    
    
    
    Накидал для вас, не проверял. Как-то так. "Ссылка" - список значений типа Документ.КомплектацияНоменклатуры (у меня не УТ). Для начала можете засунуть запрос в консоль запросов и посмотреть что вам выдает.

    Начал писать до вашего последнего сообщения, так что вот как-то так, без контроля все получилось.

Поделиться этой страницей