Базовый курс. Решение ДЗ №8
Представляем решение очередного задания.
Это “объемное” решение, состоящее из 27 видео-уроков.
К сожалению, у Вас недостаточно прав для просмотра этой записи. Если Вы еще не залогинены на сайте — залогиньтесь. Если Вы оплачивали курс, у Вас активирован токен доступа, Вы залогинены, но Вы видите эту запись — напишите нам на e-mail поддержки.
ДЗ выполнила
ДЗ 8 Выполнил, только по ценам сделал зависимый регистр сведений и организовал ввод через документ
Выполнил задание. Сначала целиком самостоятельно, затем посмотрел видео. Так может труднее, но лучше в голове откладывается, когда над чем-то “паришься”.Затем кое-что переделал, опять же по памяти. Понравился способ удаления записей из регистра с сиподьзванием массива, и использование СтрЗаменить для текста запроса. Всеми силами стараюсь догнать основной коллектив.
Мы вам даем еще один шанс догнать коллектив )
ДЗ № 8 выполнил. Единственное, при проверке наличия движений по номенклатуре сделал запрос ко всем регистрам конфигурации, чтобы получить универсальное решение. В цикле по Метаданные.РегистрыНакопления слепил запрос в котором выбрал первые записи из всех регистров, содержащих измерения с типом “СправочникСсылка.Номенклатура”.
Отлично!
ДЗ 8 выполнил
ДЗ №8 выполнил
Заранее прошу простить за длинный комментарий – вопрос. Решил всё по ДЗ №8 объединить в одну кучу.
1). в 3 видео перед проведением в запросе при обращении к виртуальной таблице
РегистрСведений.МенеджерыКонтрагентов.СрезПоследних(&Дата, Контрагент = &Контрагент) КАК МенеджерыКонтрагентовСрезПоследних”
параметр “Дата” наверное не нужен. Т.к. нам нужно лишь узнать, первый это контакт (есть ли запись по данному контрагенту в регистре сведений, любая).
Она не мешает, ну вроде и не нужна.
2). в 4 видео, в процедуре ОбработкаУдаленияПроведения(Отказ) используется код:
Для каждого Запись Из Набор Цикл
Если Запись.Документ = Ссылка Тогда
Набор.Удалить(Запись);
КонецЕсли;
КонецЦикла;
Да, в данном коде не все записи набора обрабатываются (Поэтому надо решать через Массив). Может кто нибудь подскажит, где в мастер группе рассматривалось такое поведение.
(Я этот момент пропустил).
3). в 5 видео при создании ресурса “Цена” регистра сведения и в 12 видео при создании ресурса “Количество”
регистра накопления “ОстаткиНоменклатура” нужно ли указывать свойство неотрицательное”?
А также в 10 видео в процедуре ОбработатьПересчетСуммы(Данные) есть такой код:
Если ВариантПересчетаЦена И Данные.Количество0 Тогда
……
ИначеЕсли НЕ ВариантПересчетаЦена И Данные.Цена0 Тогда
…….
Не “> 0″, а ” 0″. Т.е. предполагается что могут документы проводится с отрицательной Ценой или отрицательным Количеством.
Бывают ли такие случаи в типовых конфигурациях? Или может устанавливать в реквизитах “неотрицательное” а в программном коде “> 0”?
4). в 13 видео в запросе (для получения данных документа для проведения) используется группировка. Т.е.:
“……
СГРУППИРОВАТЬ ПО
ПоступлениеТоваровТовары.Номенклатура,
ПоступлениеТоваровТовары.Качество,
ПоступлениеТоваровТовары.Ссылка.Дата”;
Группировка по полям “Номенклатура” и “Качество” понятна (чтобы запись в результате запроса по данной комбинации измерений была одна, даже если и будут присутствовать дубли строк в документе). А вот группировка по полю “Дата” нужна ли? Документ один, дата документа одна,в табличной части документа поля “Дата” нет. В скаченной выгрузке ИБ еще присутствует группировка:
“ПоступлениеТоваровТовары.Ссылка.Контрагент” (наверное тоже лишняя).
5). Так как регистров несколько (по которым могут быть движения по номенклатуре), для проверки наличия движений использовал запрос:
“ВЫБРАТЬ
| ЗакупкиОбороты.Номенклатура
|ИЗ
| РегистрНакопления.Закупки.Обороты(, , , Номенклатура = &Номенклатура) КАК ЗакупкиОбороты
|ОБЪЕДИНИТЬ
|
|ВЫБРАТЬ
| ОстаткиТоваровОбороты.Номенклатура
|ИЗ
| РегистрНакопления.ОстаткиТоваров.Обороты(, , , Номенклатура = &Номенклатура) КАК ОстаткиТоваровОбороты
|
|ОБЪЕДИНИТЬ
|
|ВЫБРАТЬ
| ЦеныСрезПоследних.Номенклатура
|ИЗ
| РегистрСведений.Цены.СрезПоследних(, Номенклатура = &Номенклатура) КАК ЦеныСрезПоследних”;
Но есть подозрение, что даже при имеющихся движениях по номенклатуре (т.е. записи в физических таблицах присутствуют), в виртуальных таблицах (для регистров остатков) могут отсутствовать записи. Т.е. обращаясь к таблице Обороты(), мы обращаемся к таблице итогов. А в зависимости от настроек в “Управление итогов”, наверное возможно, что записей не будет. (мастер группа от 2010-07-28, видео 07)
Запрос работает, но прошу покритиковать.
6). И вопрос по получившейся конфигурации (при решении ДЗ). Закупку наверное логичнее вести в единицах стоимости. А продажу
по цене. (у нас получается в обоих случаях цена). Или вы имеете ввиду разделение делать по типу цен. Т.е. цена закупки, цена продажи?
1. Согласен, можно обойтись без параметра.
2. https://mg.spec8.ru/2010/07/16/мг-видео-от-2010-07-16/, 3 видео
3. В типовых возможности вводить отрицательные цены нет.
Но иногда на проектах реализуется механизм “отрицательных счетов-фактур”, поэтому исключать такого варианта нельзя.
Но по-умолчанию, все же лучше запретить отрицательные цены.
4. В запросе все поля должны делиться на групповые и суммируемые. Поэтому группировка не лишняя.
Более того, если в конструкторе “роль” поля не определена, то система это поле сделает групповым.
5. Да, это возможно, поэтому лучше обращаться к физическим таблицам. Кроме того, пожалуй лучше выбирать одну первую запись в каждом запросе объединения, поскольку нам нужно понять есть ли записи в принципе.
6. Идею не понял. Цена указываемая в поступлении, это то что нам выставил поставщик. А в реализации цена наша, цена продажи. Что смущает?
Спасибо за ответы. Думал забаните.
По 5:
Думаю, что не нужно выбирать первую запись в каждом запросе (т.е. “Выбрать Первые 1…”), т.к. в каждом запросе у меня уже выбирается одно поле по одной конкретной номенклатуре. Результатом одного запроса к одной виртуальной таблице Обороты(…) регистра накопления будет и так одна (или не одной) строчка. Плюс я применяю “ОБЪЕДИНИТЬ”, а не “ОБЪЕДИНИТЬ ВСЕ”. В синтакс-помощнике (Секция ОБЪЕДИНИТЬ) сказано: “По умолчанию при объединении запросов полностью одинаковые строки в результате запроса, сформированные разными запросами, заменяются одной”. Таким образом в итоге запроса будет или одна или не одной записи. (+ урок 17-23 1й блок).
По 6:
Прошу прощения сам немного запутался. Просто до вашего курса начинал изучать 8.2 по книге “Практическое пособие разработчика”. И там в документе “Приходная накладная” присутствовал реквизит “Цена”, а при списании товара в документе “Оказание услуг” реквизит “Цена” и “Стоимость”.
5. Во-первых, применять таблицу Обороты неправильно, вы сами правильно об этом сказали в исходном посте.
Во-вторых, при использовании физической таблице возможно дублирование, но на уровне первого запроса, поэтому Первые 1, можно поставить только в первом запросе объединения.
5. Да, с Вами полностью согласен. Я просто имел ввиду (не в контексте этой задачи), что если бы использовался мой вариант запроса, тогда можно “ВЫБРАТЬ ПЕРВЫЕ 1..” и не использовать.
В книге «Практическое пособие разработчика 8.2» далее реквизит “Стоимость” будет убран. Он был поставлен, пока в обработке проведения не было автоматического списания стоимости товара на складе. Надо было дальше эту книгу просмотреть.
Да, по поводу книги «Практическое пособие разработчика» – это еще по 8.0 оттуда у меня по ПВХ ничего в уме не отложилось, хотя чисто механически весь сквозной пример выполнил.
А вот пару раз посмотрел видео-обучение Е.Гилева по ПВХ и всё стало ясно и понятно.
Я как раз где-то половину этой книги и прошел (больше не успел), а после записался на эти курсы.
Да и с ПВХ (книга в редакциии 8.0) тоже в голове только каша была. Не мог понять отличия от справочников (зачем нужен этот объект). Только прояснение появилось после просмотра данного курса.
Радченко для 8.0 и 8.1 был вообще мало понятен.
Для 8.2 книга стала толще, а язык проще.
По 4:
Так и не понял зачем нужна группировка. И не совсем понятна фраза: “если в конструкторе «роль» поля не определена, то система это поле сделает групповым”.
Группировка нужна, чтобы исключить дубли, это я думаю понятно.
Проведите эксперимент: создайте запрос конструктором, обращение к табличной части, выходные поля Номенклатура и Сумма, кроме этого сделайте поле Сумма суммируемым (закладка Группировка). Далее нажимаете ОК, потом снова заходите в конструктор на закладку Группировка, наблюдаете эффект.
Вот о чем шла речь в этой фразе.
Евгений, это все я понял, и что означала ваша фраза теперь тоже. Я не понял зачем дополнительная группировка по полю “Дата”. Ведь в табличной части документа у нас нет поля “дата”. И сгруппировав по полям “Номенклатура” и “Качество” (которые присутствуют в табличной части документа) мы уже уберем все дубли строк (в разрезе этих двух “измерений”), которые были в табличной части документа. А группировка по полю “дата” уже как бы и лишняя. Есть она или нет, результат запроса от этого не изменится.
В том то и дело, что группировки не может не быть!
Давайте еще один тест. Создайте запрос конструктором, обращение к табличной части, выходные поля Номенклатура, Сумма, Ссылка.Дата, кроме этого сделайте поле Сумма суммируемым, а поле Номенклатура групповым.
“Лишнюю” дату можно не трогать. Нажимаем ОК, далее вновь в конструктор, изменилась “роль” даты?
Осмелюсь добавить свой комментарий и объяснить коллеге необходимость присутствия полей “Дата” и “Контрагент” в секции группировки запроса.
Действительно, ЛОГИЧЕСКОЙ группировки по данным полям не происходит. Эти поля нам нужны только в секции описания полей выборки для полноты результирующего набора записей запроса.
Добавление же этих полей к полям группировки происходит по причине действия стандартного правила SQL: “Если в запросе используется группировка (секция СГРУППИРОВАТЬ ПО/GROUP BY), то в списке полей выборки (секция ВЫБРАТЬ/SELECT) могут присутствовать ТОЛЬКО поля группировки И агрегатные функции”. Об этом правиле можно прочитать в любом учебнике по SQL и встроенной справке 1С (описание предложения СГРУППИРОВАТЬ ПО абзац “Важно!”).
Автоматическое же изменение “роли” полей, о которых пишет Евгений, это всего лишь реализация данного правила со стороны разработчиков конструктора запросов.
Для полноты следует отметить, что в запросах 1С есть два исключения из этого правила: первое – это получение поля в списке выборке через точку от группировочного (описано в ИТС “Особенности использования предложения СГРУППИРОВАТЬ ПО”); второе же, более интересное в данном контексте, указано в вышеупомянутом абзаце “Важно!” справки 1С явно указывает на возможность не вносить в предложение группировки поля из таблицы верхнего уровня (в данном случае таблицы шапки документа), если группировка происходит по полям вложенной таблицы (таблицы табличной части документа). Или же я неправильно понял суть, а имелись ввиду только таблицы вложенных запросов? Потому как в данном примере это исключение не работает, то есть всё работает как в стандартном SQL – выдается ошибка о несовпадении полей выборки и группировки.
P.S. Это пожалуй вопрос для МГ, но не захотел вырывать его из контекста, поэтому пишу здесь.
Вопрос интересный, просьба прислать на ящик МГ.
Коллеги, огромное спасибо за разъяснения. Я мыслил с логической точки зрения. Об этих правилах (“Важно”) конечно же не знал.
Второе исключение хорошо бы разобрать в мастер группе (привести какой нибудь пример).
Выполнил, очень понравилась ваша оптимизация!
Задание выполнил.
ДЗ № 8 выполнено
ДЗ № 8 выполнено. Особых проблем не было
ДЗ 8 выполнил
Евгений, можете выложить выгрузку ИБ, которая была в самом начале базового курса или это уже не реально?
Хочу на практике воспроизвести все примеры, которые Вы показываете по ходу курса с самого начала.
В самом начале базового курса ничего не было, конфигурация создавалась с нуля.
Можно попытаться взять конфигурацию после первого блока..
Выполнил.
Выполняю параллельно с Вашим видео. Слышу задачу – пишу. Если могут быть разные варианты решения или в чем-то не уверен – смотрю видео по этой части.
Может и не самый лучший подход, но получается довольно продуктивно и времен тратишь не многои в “скользких” моментах не теряешься.
Вопрос такой: а как можно прижать в УФ поле Сумма(итог) к правому краю формы, как в типовых? Попробовал и с группой и так в свойствах – нигде не нашел.
Хороший вопрос, здесь нужна демонстрация, задайте его в МГ, отвечу в видео..
Прогнал проверку конфигурации (своей и выложенной) – появилось две ошибки:
Документ.ПоступлениеТоваров.МодульОбъекта(12,5)}: Переменная не определена (ДвиженияПоРегистрам)
<>ДвиженияПоРегистрам.ПриходНоменклатуры(Движения, Ссылка); (Проверка толстого клиента (обычное приложение), вариант клиент-сервер)
{Документ.АвансовыйОтчет.МодульОбъекта(3,5)}: Переменная не определена (ДвиженияПоРегистрам)
<>ДвиженияПоРегистрам.ПриходНоменклатуры(Движения, Ссылка, Истина); (Проверка толстого клиента (обычное приложение), вариант клиент-сервер)
***
Т.е. в обычном приложении серверный общий модуль ДвиженияПоРегистрам почему-то не виден. А почему так? И как это дело поправить?
Уточнение: общий модуль ДвиженияПоРегистрам не виден в режиме толстого клиента как для обычного, так и для управляемого приложения.
Тут штука очень хитрая.
В обычном приложении в клиент-сервере модуль объекта исполняется на клиенте (в упр. приложении на сервере).
Поэтому с клиента не видны методы данного общего модуля.
Как их сделать видимыми? Поставить флаг “Вызов сервера”.
Сумму документа настроила в подвале, почему-то мне так больше нравится:)
Все надеялся что будет реализован обработчик при изменении типа цены в документе, чтобы посмотреть как и что правильнее вызывать. Этот вопрос решен конечно, но хотелось бы увидеть как надо!
В контекстной серверной процедуре получаем новые цены запросом. Для этого табличную часть выгружаем в таблицу значений.
Далее в запросе обращаемся к ТЗ, и к РС Цены, получаем новые данные для табличной части. После все загружаем в табличную часть.
У вас такой алгоритм?
Да, такой, я имел введу как идут обработчики? В форме в клиентской процедуре я вызываю серверную процедуру формы, которая получает объект, вызывает серверный общий модуль, последний получает цены, меняет ТЗ. Далее в сервеной процедуре формы объект преобразуется обратно в данные формы?
Я так понял нельзя передать Объект типа Данныеформы в процедуру общего модуля и там преобразовать его в объект?
Да, порядок такой.
Данные формы передавать во внеконтекстные серверные вызовы нельзя.
ДЗ №8 выполнено.
При удалении записей из регистра МенеджерыКонтрагентов может быть следующая ситуация: создано десколько документов Контакт по одному и тому же менеджеру и контрагенту. Затем распроводим первый документ и теряем информацию о взаимосвязи менеджера и контрагента. Возможно правильнее делать запись в регистр по каждому документу Контакт?
А я сравнивал ВариантПересчета с ПредопределенноеЗначение(“Перечисление.МетодыПересчета.ПересчетЦены”) на клиенте.
Нужно помнить, что ПредопределенноеЗначение это тоже вызов сервера.
Спасибо за уточнение. Учту.
Пока я не понял сути предложения, ведь запись и так делается по каждому документу, и именно она и удалится..
Да, не внимательно смотрел Ваше решение. Я сделал излишне дословно. В тексте задания указано, “при проведении необходимо выполнять анализ, если происходит *первый* контакт, то необходимо установить значение менеджера из документа”. Вы же формируете движения по каждому документу… Все ОК.
Доброго времени суток. При реализации движений в регистр при проведении документов закупки не учтено важное требование – количество в регистре храниться в базовых единицах измерения. Так что без запроса не обойтись.
Действительно, этот важный момент я упустил!
Запишу доп. видео.
Евгений, возник такой вопрос по запросу. На больших объемах данных как быстро он отработает? По идее мы выбираем только поле Номенклатура по условию, но ведь обрабатываем всю таблицу движений регистра!?
Время выполнение запроса даже на больших объемах данных должно быть приемлемым.
Поскольку происходит простое обращение к одной таблице.
1. Набор = РегистрыСведений.МенеджерыКонтрагентов.СоздатьНаборЗаписей();
2. Набор.Отбор.Контрагент.Установить(Контрагент);
3. Запись = Набор.Добавить();
4. Запись.Период = Дата;
5. Запись.Контрагент = Контрагент;
6. Запись.Менедежер = Менеджер;
7. Запись.Документ = Ссылка;
8. Набор.Записать();
VS
1. МенеджерЗаписи = РегистрыСведений.МенеджерыКонтрагентов.СоздатьМенеджерЗаписи();
2. МенеджерЗаписи.Контрагент = Контрагент;
3. МенеджерЗаписи.Менедежер = Менеджер;
4. МенеджерЗаписи.Период = Дата;
5. МенеджерЗаписи.Документ = Ссылка;
6. МенеджерЗаписи.Записать();
Согласен, 2 строки кода )
Но лично мне через набор записей работать привычней, по аналогии с другими регистрами.
А мне реально страшно теперь забыть Прочитать() и убить все данные.
Тоже аргумент.
Но самое главное не забыть установить отбор.
Не понял почему после установке отбора, не используем метод “прочитать” ?
Я что то упустил или невнимательно смотрел материал ?
И еще непонятно почему отбор устанавливается только по контрагенту. Я бы еще добавил отбор по дате.
Что то я здесь недопонял :(
Олег, вот почему:
1. Когда мы делаем запись в регистр Менеджеры из документы, мы предварительно убедились, что данных по этому контрагенту в регистре нет.
Поэтому устанавливать или нет отбор, не важно.
2. Метод Прочитать нужен нам, если мы хотим посмотреть, что есть в регистре по указанному отбору.
Но
А. Нам не нужно читать
Б. Мы и так знаем что в регистре по этому контрагенту пусто, зачем читать?
То есть это решение именно в контексте данной задачи.
Понятно.
Евгений, подскажите – отбор по дате нужно устанавливать ?
Если мы читаем данные из периодического независимого регистра сведений.
Если в регистре может быть несколько записей по одному контрагенту за разные даты (а не так как в условии нашей задачи). Я думаю что нужно, если мы хотим прочитать или перазаписать данные именно за эту дату, а не за все даты по данному контрагенту. Я прав ?
Да, верно.
Если мы не хотим, чтобы все записи по этому контрагенту заменились одной, нужно устанавливать отбор по дате.
Спасибо !
Теперь прояснилось :)
По-моему, в документе КонтактСКонтрагентом при обработке проведения проще использовать класс РегистрСведенийМенеджерЗаписи.
Использовать можно. Но только чем проще? Приведете фрагмент кода?
на 2 строки кода меньше =)
Приведите решение и посчитаем строки )