Базовый курс. Решение ДЗ №8

Представляем решение очередного задания.
Это “объемное” решение, состоящее из 27 видео-уроков.

К сожалению, у Вас недостаточно прав для просмотра этой записи. Если Вы еще не залогинены на сайте — залогиньтесь. Если Вы оплачивали курс, у Вас активирован токен доступа, Вы залогинены, но Вы видите эту запись — напишите нам на e-mail поддержки.

комментариев 65 на “Базовый курс. Решение ДЗ №8”

  1. ДЗ выполнила

  2. ДЗ 8 Выполнил, только по ценам сделал зависимый регистр сведений и организовал ввод через документ

  3. Выполнил задание. Сначала целиком самостоятельно, затем посмотрел видео. Так может труднее, но лучше в голове откладывается, когда над чем-то “паришься”.Затем кое-что переделал, опять же по памяти. Понравился способ удаления записей из регистра с сиподьзванием массива, и использование СтрЗаменить для текста запроса. Всеми силами стараюсь догнать основной коллектив.

    • Мы вам даем еще один шанс догнать коллектив )

  4. ДЗ № 8 выполнил. Единственное, при проверке наличия движений по номенклатуре сделал запрос ко всем регистрам конфигурации, чтобы получить универсальное решение. В цикле по Метаданные.РегистрыНакопления слепил запрос в котором выбрал первые записи из всех регистров, содержащих измерения с типом “СправочникСсылка.Номенклатура”.

  5. ДЗ 8 выполнил

  6. ДЗ №8 выполнил

  7. Евгений Ершов 03.08.2010 в 00:18

    Заранее прошу простить за длинный комментарий – вопрос. Решил всё по ДЗ №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. Идею не понял. Цена указываемая в поступлении, это то что нам выставил поставщик. А в реализации цена наша, цена продажи. Что смущает?

      • Евгений Ершов 03.08.2010 в 11:39

        Спасибо за ответы. Думал забаните.
        По 5:
        Думаю, что не нужно выбирать первую запись в каждом запросе (т.е. “Выбрать Первые 1…”), т.к. в каждом запросе у меня уже выбирается одно поле по одной конкретной номенклатуре. Результатом одного запроса к одной виртуальной таблице Обороты(…) регистра накопления будет и так одна (или не одной) строчка. Плюс я применяю “ОБЪЕДИНИТЬ”, а не “ОБЪЕДИНИТЬ ВСЕ”. В синтакс-помощнике (Секция ОБЪЕДИНИТЬ) сказано: “По умолчанию при объединении запросов полностью одинаковые строки в результате запроса, сформированные разными запросами, заменяются одной”. Таким образом в итоге запроса будет или одна или не одной записи. (+ урок 17-23 1й блок).

        По 6:
        Прошу прощения сам немного запутался. Просто до вашего курса начинал изучать 8.2 по книге “Практическое пособие разработчика”. И там в документе “Приходная накладная” присутствовал реквизит “Цена”, а при списании товара в документе “Оказание услуг” реквизит “Цена” и “Стоимость”.

        • 5. Во-первых, применять таблицу Обороты неправильно, вы сами правильно об этом сказали в исходном посте.
          Во-вторых, при использовании физической таблице возможно дублирование, но на уровне первого запроса, поэтому Первые 1, можно поставить только в первом запросе объединения.

          • Евгений Ершов 03.08.2010 в 13:25

            5. Да, с Вами полностью согласен. Я просто имел ввиду (не в контексте этой задачи), что если бы использовался мой вариант запроса, тогда можно “ВЫБРАТЬ ПЕРВЫЕ 1..” и не использовать.

        • В книге «Практическое пособие разработчика 8.2» далее реквизит “Стоимость” будет убран. Он был поставлен, пока в обработке проведения не было автоматического списания стоимости товара на складе. Надо было дальше эту книгу просмотреть.
          Да, по поводу книги «Практическое пособие разработчика» – это еще по 8.0 оттуда у меня по ПВХ ничего в уме не отложилось, хотя чисто механически весь сквозной пример выполнил.
          А вот пару раз посмотрел видео-обучение Е.Гилева по ПВХ и всё стало ясно и понятно.

          • Евгений Ершов 04.08.2010 в 10:28

            Я как раз где-то половину этой книги и прошел (больше не успел), а после записался на эти курсы.
            Да и с ПВХ (книга в редакциии 8.0) тоже в голове только каша была. Не мог понять отличия от справочников (зачем нужен этот объект). Только прояснение появилось после просмотра данного курса.

            • Радченко для 8.0 и 8.1 был вообще мало понятен.
              Для 8.2 книга стала толще, а язык проще.

      • Евгений Ершов 03.08.2010 в 13:31

        По 4:
        Так и не понял зачем нужна группировка. И не совсем понятна фраза: “если в конструкторе «роль» поля не определена, то система это поле сделает групповым”.

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

          • Евгений Ершов 03.08.2010 в 14:34

            Евгений, это все я понял, и что означала ваша фраза теперь тоже. Я не понял зачем дополнительная группировка по полю “Дата”. Ведь в табличной части документа у нас нет поля “дата”. И сгруппировав по полям “Номенклатура” и “Качество” (которые присутствуют в табличной части документа) мы уже уберем все дубли строк (в разрезе этих двух “измерений”), которые были в табличной части документа. А группировка по полю “дата” уже как бы и лишняя. Есть она или нет, результат запроса от этого не изменится.

            • В том то и дело, что группировки не может не быть!
              Давайте еще один тест. Создайте запрос конструктором, обращение к табличной части, выходные поля Номенклатура, Сумма, Ссылка.Дата, кроме этого сделайте поле Сумма суммируемым, а поле Номенклатура групповым.
              “Лишнюю” дату можно не трогать. Нажимаем ОК, далее вновь в конструктор, изменилась “роль” даты?

              • Осмелюсь добавить свой комментарий и объяснить коллеге необходимость присутствия полей “Дата” и “Контрагент” в секции группировки запроса.
                Действительно, ЛОГИЧЕСКОЙ группировки по данным полям не происходит. Эти поля нам нужны только в секции описания полей выборки для полноты результирующего набора записей запроса.
                Добавление же этих полей к полям группировки происходит по причине действия стандартного правила SQL: “Если в запросе используется группировка (секция СГРУППИРОВАТЬ ПО/GROUP BY), то в списке полей выборки (секция ВЫБРАТЬ/SELECT) могут присутствовать ТОЛЬКО поля группировки И агрегатные функции”. Об этом правиле можно прочитать в любом учебнике по SQL и встроенной справке 1С (описание предложения СГРУППИРОВАТЬ ПО абзац “Важно!”).
                Автоматическое же изменение “роли” полей, о которых пишет Евгений, это всего лишь реализация данного правила со стороны разработчиков конструктора запросов.

                • Для полноты следует отметить, что в запросах 1С есть два исключения из этого правила: первое – это получение поля в списке выборке через точку от группировочного (описано в ИТС “Особенности использования предложения СГРУППИРОВАТЬ ПО”); второе же, более интересное в данном контексте, указано в вышеупомянутом абзаце “Важно!” справки 1С явно указывает на возможность не вносить в предложение группировки поля из таблицы верхнего уровня (в данном случае таблицы шапки документа), если группировка происходит по полям вложенной таблицы (таблицы табличной части документа). Или же я неправильно понял суть, а имелись ввиду только таблицы вложенных запросов? Потому как в данном примере это исключение не работает, то есть всё работает как в стандартном SQL – выдается ошибка о несовпадении полей выборки и группировки.
                  P.S. Это пожалуй вопрос для МГ, но не захотел вырывать его из контекста, поэтому пишу здесь.

                • Вопрос интересный, просьба прислать на ящик МГ.

                • Евгений Ершов 04.08.2010 в 12:06

                  Коллеги, огромное спасибо за разъяснения. Я мыслил с логической точки зрения. Об этих правилах (“Важно”) конечно же не знал.
                  Второе исключение хорошо бы разобрать в мастер группе (привести какой нибудь пример).

  8. Выполнил, очень понравилась ваша оптимизация!

  9. Задание выполнил.

  10. ДЗ № 8 выполнено

  11. ДЗ № 8 выполнено. Особых проблем не было

  12. ДЗ 8 выполнил

  13. Harley Davidson 29.07.2010 в 19:21

    Евгений, можете выложить выгрузку ИБ, которая была в самом начале базового курса или это уже не реально?

    Хочу на практике воспроизвести все примеры, которые Вы показываете по ходу курса с самого начала.

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

  14. Выполнил.
    Выполняю параллельно с Вашим видео. Слышу задачу – пишу. Если могут быть разные варианты решения или в чем-то не уверен – смотрю видео по этой части.
    Может и не самый лучший подход, но получается довольно продуктивно и времен тратишь не многои в “скользких” моментах не теряешься.

    Вопрос такой: а как можно прижать в УФ поле Сумма(итог) к правому краю формы, как в типовых? Попробовал и с группой и так в свойствах – нигде не нашел.

    • Хороший вопрос, здесь нужна демонстрация, задайте его в МГ, отвечу в видео..

  15. Константин Павленко 26.07.2010 в 20:14

    Прогнал проверку конфигурации (своей и выложенной) – появилось две ошибки:
    Документ.ПоступлениеТоваров.МодульОбъекта(12,5)}: Переменная не определена (ДвиженияПоРегистрам)
    <>ДвиженияПоРегистрам.ПриходНоменклатуры(Движения, Ссылка); (Проверка толстого клиента (обычное приложение), вариант клиент-сервер)
    {Документ.АвансовыйОтчет.МодульОбъекта(3,5)}: Переменная не определена (ДвиженияПоРегистрам)
    <>ДвиженияПоРегистрам.ПриходНоменклатуры(Движения, Ссылка, Истина); (Проверка толстого клиента (обычное приложение), вариант клиент-сервер)
    ***
    Т.е. в обычном приложении серверный общий модуль ДвиженияПоРегистрам почему-то не виден. А почему так? И как это дело поправить?

    • Константин Павленко 26.07.2010 в 20:16

      Уточнение: общий модуль ДвиженияПоРегистрам не виден в режиме толстого клиента как для обычного, так и для управляемого приложения.

    • Тут штука очень хитрая.
      В обычном приложении в клиент-сервере модуль объекта исполняется на клиенте (в упр. приложении на сервере).
      Поэтому с клиента не видны методы данного общего модуля.
      Как их сделать видимыми? Поставить флаг “Вызов сервера”.

  16. Сумму документа настроила в подвале, почему-то мне так больше нравится:)

  17. Илья Чернов 26.07.2010 в 01:23

    Все надеялся что будет реализован обработчик при изменении типа цены в документе, чтобы посмотреть как и что правильнее вызывать. Этот вопрос решен конечно, но хотелось бы увидеть как надо!

    • В контекстной серверной процедуре получаем новые цены запросом. Для этого табличную часть выгружаем в таблицу значений.
      Далее в запросе обращаемся к ТЗ, и к РС Цены, получаем новые данные для табличной части. После все загружаем в табличную часть.
      У вас такой алгоритм?

      • Илья Чернов 26.07.2010 в 10:55

        Да, такой, я имел введу как идут обработчики? В форме в клиентской процедуре я вызываю серверную процедуру формы, которая получает объект, вызывает серверный общий модуль, последний получает цены, меняет ТЗ. Далее в сервеной процедуре формы объект преобразуется обратно в данные формы?

        Я так понял нельзя передать Объект типа Данныеформы в процедуру общего модуля и там преобразовать его в объект?

        • Да, порядок такой.
          Данные формы передавать во внеконтекстные серверные вызовы нельзя.

  18. Ilya Palatnikov 26.07.2010 в 00:57

    ДЗ №8 выполнено.

  19. Михайлов Сергей 25.07.2010 в 22:50

    При удалении записей из регистра МенеджерыКонтрагентов может быть следующая ситуация: создано десколько документов Контакт по одному и тому же менеджеру и контрагенту. Затем распроводим первый документ и теряем информацию о взаимосвязи менеджера и контрагента. Возможно правильнее делать запись в регистр по каждому документу Контакт?

    • Михайлов Сергей 25.07.2010 в 23:21

      А я сравнивал ВариантПересчета с ПредопределенноеЗначение(“Перечисление.МетодыПересчета.ПересчетЦены”) на клиенте.

      • Нужно помнить, что ПредопределенноеЗначение это тоже вызов сервера.

        • Михайлов Сергей 26.07.2010 в 05:42

          Спасибо за уточнение. Учту.

    • Пока я не понял сути предложения, ведь запись и так делается по каждому документу, и именно она и удалится..

      • Михайлов Сергей 26.07.2010 в 05:41

        Да, не внимательно смотрел Ваше решение. Я сделал излишне дословно. В тексте задания указано, “при проведении необходимо выполнять анализ, если происходит *первый* контакт, то необходимо установить значение менеджера из документа”. Вы же формируете движения по каждому документу… Все ОК.

  20. Доброго времени суток. При реализации движений в регистр при проведении документов закупки не учтено важное требование – количество в регистре храниться в базовых единицах измерения. Так что без запроса не обойтись.

    • Действительно, этот важный момент я упустил!
      Запишу доп. видео.

      • Евгений, возник такой вопрос по запросу. На больших объемах данных как быстро он отработает? По идее мы выбираем только поле Номенклатура по условию, но ведь обрабатываем всю таблицу движений регистра!?

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

  21. 1. Набор = РегистрыСведений.МенеджерыКонтрагентов.СоздатьНаборЗаписей();
    2. Набор.Отбор.Контрагент.Установить(Контрагент);
    3. Запись = Набор.Добавить();
    4. Запись.Период = Дата;
    5. Запись.Контрагент = Контрагент;
    6. Запись.Менедежер = Менеджер;
    7. Запись.Документ = Ссылка;
    8. Набор.Записать();
    VS
    1. МенеджерЗаписи = РегистрыСведений.МенеджерыКонтрагентов.СоздатьМенеджерЗаписи();
    2. МенеджерЗаписи.Контрагент = Контрагент;
    3. МенеджерЗаписи.Менедежер = Менеджер;
    4. МенеджерЗаписи.Период = Дата;
    5. МенеджерЗаписи.Документ = Ссылка;
    6. МенеджерЗаписи.Записать();

    • Согласен, 2 строки кода )
      Но лично мне через набор записей работать привычней, по аналогии с другими регистрами.

      • Сергей Шульженко 27.07.2010 в 23:12

        А мне реально страшно теперь забыть Прочитать() и убить все данные.

        • Тоже аргумент.
          Но самое главное не забыть установить отбор.

        • Не понял почему после установке отбора, не используем метод “прочитать” ?
          Я что то упустил или невнимательно смотрел материал ?
          И еще непонятно почему отбор устанавливается только по контрагенту. Я бы еще добавил отбор по дате.
          Что то я здесь недопонял :(

          • Олег, вот почему:
            1. Когда мы делаем запись в регистр Менеджеры из документы, мы предварительно убедились, что данных по этому контрагенту в регистре нет.
            Поэтому устанавливать или нет отбор, не важно.
            2. Метод Прочитать нужен нам, если мы хотим посмотреть, что есть в регистре по указанному отбору.
            Но
            А. Нам не нужно читать
            Б. Мы и так знаем что в регистре по этому контрагенту пусто, зачем читать?

            • То есть это решение именно в контексте данной задачи.
              Понятно.

              Евгений, подскажите – отбор по дате нужно устанавливать ?
              Если мы читаем данные из периодического независимого регистра сведений.
              Если в регистре может быть несколько записей по одному контрагенту за разные даты (а не так как в условии нашей задачи). Я думаю что нужно, если мы хотим прочитать или перазаписать данные именно за эту дату, а не за все даты по данному контрагенту. Я прав ?

              • Да, верно.
                Если мы не хотим, чтобы все записи по этому контрагенту заменились одной, нужно устанавливать отбор по дате.

  22. По-моему, в документе КонтактСКонтрагентом при обработке проведения проще использовать класс РегистрСведенийМенеджерЗаписи.

    • Использовать можно. Но только чем проще? Приведете фрагмент кода?