Подготовка к аттестации 1С:Специалист по платформе 1С 8.3. «Проблема копеек», часть 2 : определение момента последнего списания

Продолжаем решать проблему копеек, первую часть решения Вы можете посмотреть в этой статье: Что такое «Проблема копеек» и как ее решить.

Вернемся к тестовому примеру из предыдущей статьи. В документе «Расходная накладная № 1» внесем некоторые изменения – создадим строки с одинаковой номенклатурой:

Документ «Расходная накладная № 1»

Рисунок 1 – Документ «Расходная накладная № 1»

Проводим документ и в движениях по регистру видим нерешенную «проблему копеек»:

Движения по РН «Остатки номенклатуры»

Рисунок 2 – Движения по РН «Остатки номенклатуры»

При этом результат будет совершенно одинаков для каждой формулы из списка. Чтобы убедиться, достаточно посмотреть в диагностические сообщения при проведении «Расходной накладной».

Давайте разбираться, в чем дело.

Результат запроса получения данных для расчета себестоимости

Рисунок 3 – Результат запроса получения данных для расчета себестоимости

Из рисунка видим, что при обходе выборки из результата запроса условие КоличествоОстаток=КоличествоСписания для каждой строки всегда равно ложь, поэтому всегда выполняется расчет по формуле 100 * 1 / 3 = 33,33 руб.

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

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

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

Разберем, что в такой ситуации нужно изменить в алгоритме, чтобы все-таки решить «проблему копеек».

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

Рисунок 4 – Движения по РН «Остатки номенклатуры»

Из схемы видим, что можно определить, является ли списание последним, если сравнить списанное количество по детальным записям со значением КоличествоОстаток из строки итогов.

Для обхода выборки из результата запроса нам понадобятся два цикла: один для обхода по иерархии, а второй по детальным записям.

Новый листинг обработки проведения:

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

Разберем отличия алгоритма

Запрос получения данных (п. 3)

Первый запрос остался без изменений. Во втором запросе добавлены итоги по номенклатуре. В итогах подсчитаем общее количество списания по номенклатуре СУММА(Количество). По полям из таблицы остатков регистра КоличествоОстаток и СтоимостьОстаток для итогов берем максимум. Их суммировать не нужно, т.к. это и есть остатки по номенклатуре.

Обход выборки из результата запроса (п.6, 6.1 – 6.4)

Получаем результат запроса и обходим выборку в цикле.

У нас будет два цикла:

  • Внешний цикл – обход выборки по номенклатуре
  • Вложенный цикл – обход детальных записей.

В рамках итерации внешнего цикла (обхода по номенклатуре) заводим переменные СписаноКоличество и СписаноСумма. Устанавливаем их значение в 0.

В цикле по детальным записям создаем движения для записи в регистр.

Списываемое количество берем из детальных записей. Не забываем увеличить счетчик списанного количества – значение переменной СписаноКоличество.

Списание будет являться последним, если СписаноКоличество будет равно КоличествоОстаток. При последнем списании не будем рассчитывать сумму списания по формуле, а возьмем значение СуммыОстаток из строки итогов за вычетом суммы, которую мы уже успели списать и накопили в переменной СписаноСумма.

Записываем найденную сумму списания в ресурс регистра.

Не забываем увеличить значение переменной СписаноСумма.

Важно: для увеличения переменной СписаноСумма прибавляем именно значение Движение.Сумма, а не значение переменной Себестоимость. Нужно помнить, что при записи в ресурс регистра происходит автоматическое округление, а в переменной СписаноСумма нужно накапливать именно суммы в том виде, как они были записаны в регистр. Только в этом случае при последнем списании мы сможем получить с помощью формулы СуммаОстаток – СписаноСумма значение с учетом ошибки округления и, таким образом, вывести суммовой остаток по регистру в ноль.

Проверим результат

Итак, проверим результат работы нашего алгоритма. Для этого перепроведем документ «Расходная накладная № 1»:

Движения по РН «Остатки номенклатуры»

Рисунок 5 – Движения по РН «Остатки номенклатуры»

Видим, что теперь все в порядке. «Проблема копеек» решена.

Подведем итоги

Мы завершили разбор «проблемы копеек» и теперь знаем, что для ее решения и на экзамене, и в реальной практике нужно:

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

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

Хотите знать все “подводные камни” аттестации?

Эти материалы взяты из нового курса – Подготовка к аттестации 1С:Специалист по Платформе 1С:Предприятие 8.3 (2019).

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

Понравилось? Хотите больше?

Предложение актуально до вечера пятницы, 28 декабря!

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

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