Иногда бывает посмотришь на код, и думаешь "Кто это сделал, руки бы ему поотрывать", и не хочется верить что это написал ты сам еще год назад.  Решил посмотреть на решение своей первой задачи и вот что из этого вышло.
1) Модуль документа "Приходная накладная".
Движения.ОстаткиНоменклатуры.Записывать = Истина;
Движения.Себестоимость.Записывать = Истина;
 
Для Каждого ТекСтрокаСписокНоменклатуры Из СписокНоменклатуры Цикл
Движение = Движения.ОстаткиНоменклатуры.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
Движение.Период = Дата;
Движение.Номенклатура = ТекСтрокаСписокНоменклатуры.Номенклатура;
Движение.ЕдиницаИзмерения = ТекСтрокаСписокНоменклатуры.ЕдиницаИзмерения;
Движение.Склад = Склад;
Движение.Количество = ТекСтрокаСписокНоменклатуры.Количество;
КонецЦикла;
 
Для Каждого ТекСтрокаСписокНоменклатуры Из СписокНоменклатуры Цикл
Движение = Движения.Себестоимость.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
Движение.Период = Дата;
Движение.Номенклатура = ТекСтрокаСписокНоменклатуры.Номенклатура;
Движение.ЕдиницаИзмерения = ТекСтрокаСписокНоменклатуры.ЕдиницаИзмерения;
Движение.Количество = ТекСтрокаСписокНоменклатуры.Количество;
Движение.Сумма =ТекСтрокаСписокНоменклатуры.Сумма;
КонецЦикла;
 
  
1) Модуль документа "Приходная накладная".
Движения.ОстаткиНоменклатуры.Записывать = Истина;
Движения.Себестоимость.Записывать = Истина;
Для Каждого ТекСтрокаСписокНоменклатуры Из СписокНоменклатуры Цикл
Движение = Движения.ОстаткиНоменклатуры.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
Движение.Период = Дата;
Движение.Номенклатура = ТекСтрокаСписокНоменклатуры.Номенклатура;
Движение.ЕдиницаИзмерения = ТекСтрокаСписокНоменклатуры.ЕдиницаИзмерения;
Движение.Склад = Склад;
Движение.Количество = ТекСтрокаСписокНоменклатуры.Количество;
КонецЦикла;
Для Каждого ТекСтрокаСписокНоменклатуры Из СписокНоменклатуры Цикл
Движение = Движения.Себестоимость.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
Движение.Период = Дата;
Движение.Номенклатура = ТекСтрокаСписокНоменклатуры.Номенклатура;
Движение.ЕдиницаИзмерения = ТекСтрокаСписокНоменклатуры.ЕдиницаИзмерения;
Движение.Количество = ТекСтрокаСписокНоменклатуры.Количество;
Движение.Сумма =ТекСтрокаСписокНоменклатуры.Сумма;
КонецЦикла;
Зачем 2 цикла? Конечно же все нужно запихнуть в 1 цикл.
Переходим к "Расходной накладной".
2)   Для каждого Стр Из СписокНоменклатуры Цикл
  Если Стр.Номенклатура.ВидТовара = Перечисления.ВидыНоменклатуры.Услуга Тогда
   Продолжить;
  КонецЕсли;
Это неявный запрос в цикле. При такой конструкции каждый раз СУБД строит запрос в которой соединяет таблицу "Номенклатуры" с таблицей "ВидНоменклатуры". При большом количестве строк замедление может быть заметным.
Ил ладно бы еще эта проверка была нужна, но в запросе и так указано условие 
РасходнаяНакладнаяСписокНоменклатуры.Номенклатура.ВидТовара <> &ВидТовара
Так зачем же еще в было цикле добавлять это?.
Кроме того в условиях лучше использовать проверку на равенство, вместо условий "Не", "Не В", "< >".
3)  Можно было бы использовать ЗаполнитьЗначенияСвойств вместо
  Движение = Движения.ОстаткиНоменклатуры.ДобавитьРасход();
  Движение.Период           = Дата;
  Движение.Склад            = Склад;
  Движение.Номенклатура            = Стр.Номенклатура;
  Движение.ЕдиницаИзмерения = Стр.ЕдиницаИзмерения;
  Движение.Количество       = Стр.Количество;
но это не окажет никакого заметного влияния на производительность.
4) В самом начале табличная часть документа помещается во временную таблицу. И это хорошо. Но временную таблицу нужно индексировать по всем полям, которые будут участвовать в дальнейшем соединениях таблиц, а до изменений было только по номенклатуре.
5) В первом запросе есть неоптимальность которая называется "Соединение с виртуальной таблицей". Временная таблица соединялась с виртуальной. А ВТ тут вообще и не нужна, так как мы ни одного поля из нее не извлекаем.
Оптимальнее будет так:
ВЫБРАТЬ
 ЕСТЬNULL(ОстаткиНоменклатурыОстатки.КоличествоОстаток, 0) КАК ОстатокКол,
 ОстаткиНоменклатурыОстатки.Номенклатура.Представление,
 ОстаткиНоменклатурыОстатки.Номенклатура КАК Номенклатура,
 ОстаткиНоменклатурыОстатки.Склад КАК Склад,
 ОстаткиНоменклатурыОстатки.ЕдиницаИзмерения КАК ЕдиницаИзмерения
ИЗ
 РегистрНакопления.ОстаткиНоменклатуры.Остатки(
   &ТочкаИтогов,
   (Склад, Номенклатура, ЕдиницаИзмерения) В
    (ВЫБРАТЬ
     ДокТЧ.Склад,
     ДокТЧ.Номенклатура,
     ДокТЧ.ЕдиницаИзмерения
    ИЗ
     ДокТЧ)) КАК ОстаткиНоменклатурыОстатки
ГДЕ
 ОстаткиНоменклатурыОстатки.КоличествоОстаток < 0
6)        Блокировка = Новый БлокировкаДанных;
 ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.ОстаткиНоменклатуры");
 ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
 ЭлементБлокировки.ИсточникДанных = СписокНоменклатуры ;
 ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Номенклатура", "Номенклатура");
 Блокировка.Заблокировать(); 
Я вообще-то не пью и не курю,но глядя на это верится с трудом) 
Блокировка не того регистра. Нужно блокировать регистр "СебестоимостьНоменклатуры".
7) Во втором запросе та же проблема, что и в первом "Соединение с виртуальной таблицей".
В отличие от первого запроса,в этом пригодятся поля из ВТ. Поэтому лучше поступить так.
Первым запросом пакета данные из виртуальной таблицы помещаем во ВТ и затем во втором запросе соединим полученные ВТ.
Запрос примет следующий вид:
ВЫБРАТЬ
 ДокТЧ.Номенклатура,
 ДокТЧ.ЕдиницаИзмерения,
 ДокТЧ.Количество,
 ДокТЧ.Склад,
 ЕСТЬNULL(СебестоимостьОстатки.КоличествоОстаток, 0) КАК ОстатокКол,
 СебестоимостьОстатки.Номенклатура.Представление,
 ЕСТЬNULL(СебестоимостьОстатки.СуммаОстаток, 0) КАК ОстатокСум
ИЗ
 ДокТЧ КАК ДокТЧ
  ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Себестоимость.Остатки(
    &ТочкаИтогов,
    Номенклатура В
     (ВЫБРАТЬ РАЗЛИЧНЫЕ
      ДокТЧ.Номенклатура
     ИЗ
      ДокТЧ)) КАК СебестоимостьОстатки
  ПО ДокТЧ.Номенклатура = СебестоимостьОстатки.Номенклатура
   И ДокТЧ.ЕдиницаИзмерения = СебестоимостьОстатки.ЕдиницаИзмерения
8)  Не решена "Проблема копеек".
               Если   Выборка.ОстатокКол <> 0 Тогда
   Движение.Сумма = (Выборка.ОстатокСум/ Выборка.ОстатокКол) *Выборка.Количество;
  КонецЕсли;
нужно как-то так
               Если Выборка.ОстатокКол =Выборка.Количество Тогда
   Движение.Сумма = Выборка.ОстатокСум;
  ИначеЕсли    Выборка.ОстатокКол <> 0 Тогда
   Движение.Сумма = (Выборка.ОстатокСум/ Выборка.ОстатокКол) *Выборка.Количество;
  КонецЕсли;
9)  Есть еще ошибка.
//Запрос.Параметры.Вставить("ТочкаИтогов", МоментВремени());
Дело тут в чем.  Когда мы очищаем движения методом "очистить" старые движения еще "висят" в памяти. И если мы оперативно перепроведем документ то получим ошибку, так как на остатках товар не появился. 
Следует добавить очистку регистра при оперативном проведении
 Если РежимПроведения = РежимПроведенияДокумента.Оперативный Тогда
 Движения.Себестоимость.Записать(); 
 КонецЕсли;
10)  Если РежимПроведения = РежимПроведенияДокумента.Оперативный Тогда
  Движения.Себестоимость.БлокироватьДляИзменения = Истина;
 КонецЕсли; 
Эти строчки кода демонстрируют полное непонимание назначение свойства "БлокироватьДляИзменения", которое никак не связано с режимом проведения.
Свойство "БлокироватьДляИзменения" позволяет параллельно записывать одинаковые наборы данных в регистр, но использовать его нет большого смысла если после записи идет проверка остатков. Кроме того использование этого свойства может привести к взаимоблокировке по причине повышения уровня изоляции. Таким образом Для регистра "ОстаткиНоменклатуры" можно вообще отключить это свойство в регистре.(Так как после записи идет проверка). А для регистра "Себестоимость" такой проверки нет и это свойство имеет смысл установить. 
11) В отчете соединения виртуальных таблиц, что тоже не очень хорошо, лучше бы как и в документе помещать данные виртуальных таблиц во временные таблицы, которые между собой потом соединить.(Но этого я уже делать не буду).
Возможно остались еще какие-то моменты, но пока достаточно как мне кажется.
 
Отчет неправильный
ОтветитьУдалить