Продвинутый курс. Домашнее задание №11
Эта запись посвящена второму потоку продвинутого курса по программированию.
Для выполнения рекомендуется изучить следующие главы 2-го блока.
Глава 1. Документы.
Глава 2. Регистры.
К сожалению, у Вас недостаточно прав для просмотра этой записи. Если Вы еще не залогинены на сайте
— залогиньтесь.
— залогиньтесь.
Если не активировали токен — посмотрите видео-инструкцию (видео N5)
Если вы залогинены, у Вас активирован токен доступа, но вы все равно видите эту запись —
напишите нам на e-mail поддержки.
Задание выполнил. Подписки на событие знакомый объект, сложностей не было.
Задание выполнил.
В подписке на событие ПередЗаписьюСписания (Источник: ДокументОбъект.СписаниеТМЦ, Событие: ПередЗаписью) в дополнительные свойства документа СписаниеТМЦ помещается таблица значений со «старыми» движениями документа по регистру ОстаткиТоваров:
<code>
Процедура ПередЗаписьюСписанияПередЗаписью(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
“ВЫБРАТЬ
| ОстаткиТоваров.Номенклатура,
| СУММА(ОстаткиТоваров.Количество) КАК Количество
|ИЗ
| РегистрНакопления.ОстаткиТоваров КАК ОстаткиТоваров
|ГДЕ
| ОстаткиТоваров.Регистратор = &Регистратор
|
|СГРУППИРОВАТЬ ПО
| ОстаткиТоваров.Номенклатура”;
Запрос.УстановитьПараметр(“Регистратор”, Источник.Ссылка);
Результат = Запрос.Выполнить();
Если Результат.Пустой() Тогда
ТаблицаДвижений = Новый ТаблицаЗначений;
ТаблицаДвижений.Колонки.Добавить(“Номенклатура”);
ТаблицаДвижений.Колонки.Добавить(“Количество”);
Иначе
ТаблицаДвижений = Результат.Выгрузить();
КонецЕсли;
Источник.ДополнительныеСвойства.Вставить(“ТаблицаДвижений”, ТаблицаДвижений);
КонецПроцедуры
</code>
Затем, в подписке на событие ОбработкаПроведенияСписания (Источник: ДокументОбъект.СписаниеТМЦ, Событие: ОбработкаПроведения) сравниваются старые и новые движения документа по регистру ОстаткиТоваров, и выполняется проверка на отрицательные остатки по изменным позициям. В случае обнаружения отрицательных остатков параметру Отказ присваивается значение и документ не проводится:
<code>
Процедура ОбработкаПроведенияСписанияОбработкаПроведения(Источник, Отказ, РежимПроведения) Экспорт
СтараяТаблицаДвижений = 0;
Если Источник.ДополнительныеСвойства.Свойство(“ТаблицаДвижений”, СтараяТаблицаДвижений) <> Неопределено Тогда
МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос.Текст =
“ВЫБРАТЬ
| СтараяТаблДвижений.Номенклатура,
| СтараяТаблДвижений.Количество
|ПОМЕСТИТЬ СтарыеДвижения
|ИЗ
| &СтараяТаблДвижений КАК СтараяТаблДвижений
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ОстаткиТоваров.Номенклатура,
| СУММА(ОстаткиТоваров.Количество) КАК Количество
|ПОМЕСТИТЬ НовыеДвижения
|ИЗ
| РегистрНакопления.ОстаткиТоваров КАК ОстаткиТоваров
|ГДЕ
| ОстаткиТоваров.Регистратор = &Регистратор
|
|СГРУППИРОВАТЬ ПО
| ОстаткиТоваров.Номенклатура
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| НовыеДвижения.Номенклатура,
| НовыеДвижения.Количество – ЕСТЬNULL(СтарыеДвижения.Количество, 0) КАК Количество
|ПОМЕСТИТЬ ИзмененныеПозиции
|ИЗ
| НовыеДвижения КАК НовыеДвижения
| ЛЕВОЕ СОЕДИНЕНИЕ СтарыеДвижения КАК СтарыеДвижения
| ПО НовыеДвижения.Номенклатура = СтарыеДвижения.Номенклатура
|ГДЕ
| НовыеДвижения.Количество – ЕСТЬNULL(СтарыеДвижения.Количество, 0) <> 0
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ОстаткиТоваровОстатки.Номенклатура,
| ОстаткиТоваровОстатки.КоличествоОстаток
|ИЗ
| РегистрНакопления.ОстаткиТоваров.Остатки(
| ,
| Номенклатура В
| (ВЫБРАТЬ
| ИзмененныеПозиции.Номенклатура
| ИЗ
| ИзмененныеПозиции КАК ИзмененныеПозиции)) КАК ОстаткиТоваровОстатки
|ГДЕ
| ОстаткиТоваровОстатки.КоличествоОстаток < 0”;
Запрос.УстановитьПараметр(“СтараяТаблДвижений”, СтараяТаблицаДвижений);
Запрос.УстановитьПараметр(“Регистратор”, Источник.Ссылка);
Результат = Запрос.Выполнить();
Если НЕ Результат.Пустой() Тогда
Отказ = Истина;
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить(“По номенклатуре ” + Выборка.Номенклатура + ” образовался отрицательный остаток в количестве ” + Выборка.КоличествоОстаток);
КонецЦикла;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
</code>
В модуле объекта документа СписаниеТМЦ в процедуре ОбработкаПроведения явным образом записываю движения по регистру ОстаткиТоваров для того чтобы в подписке на событие ОбработкаПроведенияСписания запросы к таблицам регистра ОстаткиТоваров возвращали результат с учетом движений текущего документа.
Задание выполнил. Не так универсально как в эталонном решении, зато проще (все в подписке на ОбработкаПроведения). В этой подписке у нас доступен уже записанный документ (его табличная часть), СТАРОЕ состояние движений по регистру и уже НОВОЕ состояние после ПРИНУДИТЕЛЬНОЙ записи (ведь после ОбработкаПроведения не идет автоматическая запись наборов, если дальше идут подписки на это событие) .
Процедура ПодпискаНаСобытие1ОбработкаПроведения(Источник, Отказ, РежимПроведения) Экспорт
Запрос = Новый Запрос;
МенеджерВТ=Новый МенеджерВременныхТаблиц;
Запрос.МенеджерВременныхТаблиц=МенеджерВТ;
Запрос.Текст=”ВЫБРАТЬ
| РеализацияТоваровИУслугТовары.Номенклатура,
| СУММА(РеализацияТоваровИУслугТовары.Количество) КАК Количество,
| МИНИМУМ(РеализацияТоваровИУслугТовары.НомерСтроки) КАК НомерСтроки
|ПОМЕСТИТЬ ВТТовары
|ИЗ
| Документ.РеализацияТоваровИУслуг.Товары КАК РеализацияТоваровИУслугТовары
|ГДЕ
| РеализацияТоваровИУслугТовары.Ссылка = &Ссылка
|
|СГРУППИРОВАТЬ ПО
| РеализацияТоваровИУслугТовары.Номенклатура
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ОстаткиТоваров.Номенклатура,
| ОстаткиТоваров.Количество КАК КоличествоВНаборе
|ПОМЕСТИТЬ ВТНабора
|ИЗ
| РегистрНакопления.ОстаткиТоваров КАК ОстаткиТоваров
|ГДЕ
| ОстаткиТоваров.Регистратор = &Ссылка
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТТовары.Номенклатура,
| ВТТовары.Количество,
| ВТТовары.НомерСтроки
|ПОМЕСТИТЬ ВТОбщая
|ИЗ
| ВТТовары КАК ВТТовары
|
|ОБЪЕДИНИТЬ ВСЕ
|
|ВЫБРАТЬ
| ВТНабора.Номенклатура,
| -ВТНабора.КоличествоВНаборе,
| 0
|ИЗ
| ВТНабора КАК ВТНабора
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТОбщая.Номенклатура,
| СУММА(ВТОбщая.Количество) КАК Количество,
| МАКСИМУМ(ВТОбщая.НомерСтроки) КАК НомерСтроки
|ПОМЕСТИТЬ ВТИтог
|ИЗ
| ВТОбщая КАК ВТОбщая
|
|СГРУППИРОВАТЬ ПО
| ВТОбщая.Номенклатура
|
|ИМЕЮЩИЕ
| СУММА(ВТОбщая.Количество) > 0″;
Запрос.УстановитьПараметр(“Ссылка”, Источник.Ссылка);
Результат= Запрос.Выполнить();
Источник.Движения.ОстаткиТоваров.Записать();
Запрос.Текст=”ВЫБРАТЬ
| ОстаткиТоваровОстатки.Номенклатура,
| ОстаткиТоваровОстатки.КоличествоОстаток,
| ВТИтог.НомерСтроки
|ИЗ
| РегистрНакопления.ОстаткиТоваров.Остатки(
| &МоментВремени,
| Номенклатура В
| (ВЫБРАТЬ
| ВТИтог.Номенклатура
| ИЗ
| ВТИтог КАК ВТИтог)) КАК ОстаткиТоваровОстатки
| ЛЕВОЕ СОЕДИНЕНИЕ ВТИтог КАК ВТИтог
| ПО ОстаткиТоваровОстатки.Номенклатура = ВТИтог.Номенклатура
|ГДЕ
| ОстаткиТоваровОстатки.КоличествоОстаток < 0″;
Запрос.УстановитьПараметр(“МоментВремени”,Новый Граница(Источник.МоментВремени(),ВидГраницы.Включая));
Результат=Запрос.Выполнить();
Если Не Результат.Пустой() Тогда
Отказ=Истина;
Выборка=Результат.Выбрать();
Пока Выборка.Следующий() Цикл
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = “Для проведения товара “+Выборка.Номенклатура+” недостаточно “+(-Выборка.КоличествоОстаток);
Сообщение.Поле = “Товары[“+(Выборка.НомерСтроки-1)+”].Количество”;
Сообщение.УстановитьДанные(Источник);
Сообщение.Сообщить();
КонецЦикла;
КонецЕсли;
КонецПроцедуры
ДЗ Выполнено.
Основная идея следующая: в подписке на событие ПередЗаписью проверяю Источник: 1) если не проведен – следовательно нужно делать контроль всех позиций (т.к. мы уже не знаем в каком состоянии он находился до изменения) 2) если уже проведен, значит это перепроведение и нужен контроль только измененных (или добавленных строк. Реализовал выгрузкой ТЧ Товары в ТЗ и далее запросом в временную таблицу, к которой левым соединением притягиваю таблицу по товарам из базы и сравниваю количество (разумеется прогоняя через ЕстьNULL). Результат запроса с измененными товарами выгружаю затем в массив, который передаю в структуру ДополнительныеСвойства Источника; 3) если не проведен и режим – Запись, контроль вообще не нужен.
Затем в подписке на событие ОбработкаПроведения проверяю структуру ДополнительныеСвойства на наличие массива с номенклатурой для контроля и если он не пустой – то выбираю запросом остатки указанной номенклатуры из регистра, с количеством < 0, и если запрос не пустой – выставляю Отказ = Истина и вывожу диагностику пользователю.
Задание выполнил! Использовал документ реализация товаров, в модуле проведения которого уже реализована новая технология проведения.
Для того чтобы выполнить условия задания : использовать подписку на события и контролировать только измененные по количеству товары принял след. алгоритм :
1. в подписке на события перед записью я определяю измененные по количеству товары.
2.в подписке на события обработка проведения я провожу контроль только этих измененных позиций.
Реализация:
п1. использовал запрос для анализа текущего и предыдущего состояния документа. Текущее состояние я получил выгрузив таблицу товары в таблицу значений а затем запросом к этой таблице и документу реализацияТоваров получил различия по количеству. Результат сохранил в таблицу значений и записал в ДополнительныеСвойтсва документа.
п2.В обработке проведения выполняются движения без проверки в регистр. А по окончании подключается обработчик события который анализирует на отрицательные остатки в регистре используя фильтр по товарам, который хранится в таблице значений (из дополнительныхСвойств). Предварительно я ее выгружаю в МассивТоваров
ДЗ выполнено
1. Создал подписку на событие “ПередЗаписью” для документа “Реализация товаров и услуг”. Обработчик разместил в общем серверном модуле. В обработчике выполняется запрос к Источнику (тип ДокументОбъект), где во временную таблицу помещается измененная табличная часть. Чтобы получить табличную часть до изменения, сделал запрос к Источник.Ссылка (тип ДокументСсылка) и поместил результат во временную таблицу. Затем сравнивая эти ВТ определяю строки, которые были изменены/добавлены. При этом, если в строке было изменено количество в меньшую сторону по сравнению с тем, что было, то она в расчет не берется. Результат запроса сохраняю в массив “МассивТовары”. Далее этот массив сохраняю в одноименное свойство “Товары” структуры ДополнительныеСвойства Источника:
ДопСвойства = Источник.ДополнительныеСвойства;
ДопСвойства.Вставить(“Товары”, МассивТовары);
2. Создал подписку на событие “ОбработкаПроведения” для документа “Реализация товаров и услуг”. Обработчик разместил в общем серверном модуле. Т.к. обработчик подписки срабатывает после обработки проведения документа, то для выполнения контроля отрицательных остатков достаточно запросом обратиться на момент времени документа к таблице остатков “ОстаткиТоваров.Остатки”. По условию задачи требуется обрабатывать только те товары, по которым были какие-то изменения в документе-источнике. Поэтому контроль выполняю, только если у структуры ДополнительныеСвойства есть свойство “Товары”: Источник.ДополнительныеСвойства.Свойство(“Товары”) = истина
Далее в запросе накладываю фильтр по номенклатуре из значений свойства “Товары”. Если отрицательные остатки обнаружены, вывожу об этом сообщение пользователю и отменяю проведение Отказ = истина.
Создал подписку на событие «Перед Записью» в качестве источника указал документ «Реализация товаров и услуг» в этом обработчике я с помощью запроса сравниваю текущее состояние табличной части «Товары» с записанной ТЧ в БД. Запрос похож на аналогичный запрос из ДЗ 1. Только там мы сравнивали изменение цен, кроме того отличия данного запроса заключается в том, что происходит группировка по Номенклатуре с суммированием количества (т.е. дубли допускаются) и результатом итогового запроса являются только те позиции которых либо не было в сохраненной ТЧ либо количество в новой ТЧ больше количества в сохраненной. Результат запроса я выгружаю в массив значений и добавляю в структуру «Дополнительные свойства» для передачи другому обработчику.
Поскольку запись движений уже реализована в обработчике событии «Обработка проведения», а подписка «Обработка проведения» выполняется после отработки этого обработчика, то в этой подписке остается проверить отрицательные остатки с фильтром по позициям номенклатуры переданным через Дополнительные свойства и если минусы имеются, то выдать диагностическое сообщение о нехватке товара и переменной Отказ присвоить значение Истина. Всю эту проверку имеет смысл проводить в том случае если в структуре Дополнительные свойства имеется ключ «Товары». Для реализации такой проверки удобно использовать метод структуры «Свойство».
1.Сделал подписку на событие “ПередЗаписью” документа “Реализация товаров”
2.Из подписки вызываю функцию КонтрольОстатков(Источник), которая возвращает “Истина” если с остатками всё нормально и “Ложь” иначе. Функция создана в целях универсальности, если её чуть-чуть доработать – она сможет производить аналогичную проверку для поступления.
3.1.В функции выгружаю в одну таблицу значений колонки “Номенклатура” и “Количество” Источник.Ссылка.ПолучитьОбъект().Товары
во вторую те-же колонки из Источник.Товары
сортирую обе таблицы значений, в хотром цикла обхожу обе одновременно, если в первой таблице есть элемент которого нет во второй или если в ней кол-во больше чем во второй – сохраняю всё это в третью таблицу.
3.2.В запросе на моент времени объекта Источник отбираю остатки из виртуальной таблицы “РегистрНакопления.ОстаткиТоваров.Остатки” по итогам выгруженых остатков если есть нехватка – Вывожу сообщением список номенклатуры по которой сколько единиц не хватает, если такой список пустой . Взависимости от наличия таких позиций возвращаю или истина или ложь.
Н-да , получается что прерываю не проведение а запись… В целом по нормальному следует сделать сделать всё-же доп реквизит документа, т.к. если использовать дополнительные свойства, то если я записал документ но не стал проводитьь, а проводить его потом – то всякие допсвойства не помогут, если даже извернуться сохранять в параметрах сеанса – проводить можно в другом сеансе или при другом запуске…
Или я что-то в задании не понял?
А есть и другой вариант – посмотреть в сторону модуля набора записей.
Что и сделано в решении, которое скоро выложим..
Из модуля набора записей регистра обрабатывать перепроведение документа? Всёравно не понимаю как отловить если оменили проведение в 1 сеансе, отредактировали в другом а провели в третьем… нужно будет посмотреть.
Выполнил.
1.Создал подписку на событие перед записью документа реализации. В обработчике запросом помещаю ТЧ Товары во временную таблицу ТоварыПередЗаписью, запрос связываю с менеджером ВТ, а сам менеджер передается через дополнительные свойства документа-источника.
2.Создал подписку на событие при проведении документа реализации. Получаю менеджер ВТ из доп.свойств документа-источника, запросом получаю ТЧ Товары документа и помещаю во ВТ ТоварыПриПроведении. Далее создаю описание ВТ ТоварыПередЗаписью, сохраненной в менеджере ВТ. Сравнением на неравенство количества из обеих ВТ отбирается проверяемая номенклатура и помещается в ВТ ТоварыКонтроль.
Далее реализую контроль остатков по новой технологии, а номенклатуру в запросе к регистру получаю из ВТ ТоварыКонтроль.
Неверно указана рубрика.
Спасибо, исправлено.