Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Павел Чистов. Конспект к курсу Комплексная подг...docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
28.21 Mб
Скачать

Занятие 1.12

Можно ли добавить в регистр накопления «Остатки товаров» дополнительное измерение по складам?

Купим на склады ложки: на один склад – по 100 рублей, а на второй – по 200.

Продадим одну ложку. Списываем по средневзвешенной скользящей:

То, что остаток на складе выражен только в суммовом эквиваленте – это не правильно.

Продадим ложку и со второго склада. Причем, себестоимость рассчитается внешне правильно:

А что, если рассчитывать среднее по складу?

Допустим, два склада стоят рядом. Но себестоимость списания нужна для оценки прибыли. А в данной ситуации получается, что мы, в зависимости от склада, получим абсолютно разный результат. Учитывать стоимость внутри склада имеет смысл для автономных складов

Т.е. хранить остатки в разрезе складов в регистре «Остатки товаров» не совсем правильно в данном примере.

Надо создать новый регистр накопления «Остатки по складам»:

Предварительно создадим справочник «Склады»:

Свойство

Значение

Имя

Склады

Синоним

Склады

Представление объекта

Склад

Свойство

Значение

Имя

ОстаткиПоСкладам

Синоним

Остатки по складам

Закладка «Данные»

Измерения

Номенклатура

Имя

Номенклатура

Синоним

Номенклатура

Тип

СправочникСсылка.Номенклатура

Запрет незаполненных значений

Истина

Склад

Имя

Склад

Синоним

Склад

Тип

СправочникСсылка.Склады

Запрет незаполненных значений

Истина

Ресурсы

Количество

Имя

Количество

Синоним

Количество

Тип

Число 12, 3

Регистраторами будут оба документа:

Чтобы формировать движения по регистру, надо чтобы в документах были аналогичные реквизиты. Добавим в документы реквизит «Склад»:

Свойство

Значение

Имя

Склад

Синоним

Склад

Тип

СправочникСсылка.Склады

Проверка заполнения

Выдавать ошибку

Поправим модуль объекта:

Процедура ОбработкаПроведения(Отказ, Режим)

Движения.ЗакупочныеЦены.Записывать = Истина;

Движения.ОстаткиТоваров.Записывать = Истина;

Движения.ОстаткиПоСкладам.Записывать = Истина;

Движения.ЗакупочныеЦены.Очистить();

Движения.ОстаткиТоваров.Очистить();

Движения.ОстаткиПоСкладам.Очистить();

Для Каждого ТекСтрокаТовары Из Товары Цикл

Движение = Движения.ЗакупочныеЦены.Добавить();

Движение.Период = Дата;

Движение.Номенклатура = ТекСтрокаТовары.Номенклатура;

Движение.Контрагент = Контрагент;

Движение.Цена = ТекСтрокаТовары.Цена;

Движение = Движения.ОстаткиТоваров.ДобавитьПриход();

Движение.Период = Дата;

Движение.Номенклатура = ТекСтрокаТовары.Номенклатура;

Движение.Количество = ТекСтрокаТовары.Количество;

Движение.Стоимость = ТекСтрокаТовары.Сумма;

Движение = Движения.ОстаткиПоСкладам.ДобавитьПриход();

Движение.Период = Дата;

Движение.Номенклатура = ТекСтрокаТовары.Номенклатура;

Движение.Количество = ТекСтрокаТовары.Количество;

Движение.Склад = Склад;

КонецЦикла;

КонецПроцедуры

Добавим реквизит «Склад» на форму и изменим вид формы. Добавим команду на открытие сформированных движений по регистру «Остатки по складам»:

Свойства группировочных папок в форме:

Свойство

Значение

Отображение

Нет

Группировка

Горизонтальная

ОтображатьЗаголовок

Ложь

В режиме исполнения:

Отменим проведение у всех Расходных документов. Добавим склады «Парнас» и «Шушары», укажем их в Приходных документах и перепроведем их:

Первый документ:

Второй документ:

Построим отчет, наглядно отображающий где какие товары лежат:

Отчет «Складские остатки»

Свойство

Значение

Имя

СкладскиеОстатки

Синоним

Складские остатки

Откроем СКД:

Добавим «Набор данных-запрос» и откроем «Конструктор запроса»:

В СКД:

На закладке «Настройки» сформируем основной вариант отчета (конструктором):

Итого настройки:

В режиме исполнения:

Итоги считаются только по Номенклатуре. По Складу итоги не считаются, т.к. в СКД, на закладке «Ресурсы» у ресурса «Количество»:

Свойство

Значение

Рассчитывать по

Номенклатура

Надо выводить по складу не только количество, но и стоимость товара:

В СКД:

Добавим еще один «Набор данных-запрос» и откроем «Конструктор запроса»:

Переименуем поля:

И нажмем «ОК».

Наборы данных свяжем вместе по полю «Номенклатура» - закладка «Связи наборов данных». Здесь всегда указывается только ЛЕВОЕ соединение:

  • Источник связи – основная таблица.

  • Приемник связи – присоединяемая таблица.

Связываем по Номенклатуре. При этом важно, чтобы остатки были рассчитаны на один и тот же период.

Рассчитаем стоимость склада – закладка «Вычисляемые поля»:

Настроим Оформление этого поля, а именно «Формат», т.к. значение может получиться дробным, а дробная часть в периоде:

Итого поле:

В «Выражение» можно к формуле добавить проверку на ноль:

ВЫБОР КОГДА КоличествоОстаток < 0 ТОГДА 0

КОГДА ЕСТЬNULL(КоличествоОбщ,0) = 0 ТОГДА 0

ИНАЧЕ КоличествоОстаток / КоличествоОбщ * СтоимостьОбщ

КОНЕЦ

Стоимость – это тоже ресурс. Будет подсчитываться по всем измерениям (Склады и Номенклатура):

Переименуем поле «КоличествоОстаток» в «Количество»:

На закладке «Настройки» поместим «Стоимость» в «Выбранные поля», т.е. отобразим:

В режиме исполнения:

Реализуем продажу товара с определенного склада с контролем отрицательных остатков:

При проведении документа «Расходная» будем делать проверку, хватает ли на конкретном складе определенного товара.

Перейдем в режим исполнения и откроем «Консоль запросов». Покажем, как использовать запрос наиболее корректно:

Обратимся к документу и выберем поля табличной части:

ВЫБРАТЬ

*

ИЗ

Документ.Расходная.Товары

Будем продавать товары по первому документу:

ВЫБРАТЬ

*

ИЗ

Документ.Расходная.Товары

ГДЕ

Ссылка = &Ссылка

Для расчета себестоимости товаров обратимся к регистру накопления «Остатки товаров»:

ВЫБРАТЬ

*

ИЗ

Документ.Расходная.Товары КАК ДокТЧ

ЛЕВОЕ СОЕДИНЕНИЕ

РегистрНакопления.ОстаткиТоваров.Остатки КАК Остатки

ПО

ДокТЧ.Номенклатура = Остатки.Номенклатура

ГДЕ

Ссылка = &Ссылка

Привяжем еще одну таблицу – с остатками товаров на складах:

ВЫБРАТЬ

*

ИЗ

Документ.Расходная.Товары КАК ДокТЧ

ЛЕВОЕ СОЕДИНЕНИЕ

РегистрНакопления.ОстаткиТоваров.Остатки КАК Остатки

ПО

ДокТЧ.Номенклатура = Остатки.Номенклатура

ЛЕВОЕ СОЕДИНЕНИЕ

РегистрНакопления.ОстаткиПоСкладам.Остатки КАК ОстаткиСКЛ

ПО

ДокТЧ.Номенклатура = ОстаткиСКЛ.Номенклатура

ГДЕ

Ссылка = &Ссылка

Т.к. склады разные, то система задублировала данные.

Получим остатки по конкретному складу – установим условие отбора в параметрах виртуальной таблицы:

ВЫБРАТЬ

*

ИЗ

Документ.Расходная.Товары КАК ДокТЧ

ЛЕВОЕ СОЕДИНЕНИЕ

РегистрНакопления.ОстаткиТоваров.Остатки КАК Остатки

ПО

ДокТЧ.Номенклатура = Остатки.Номенклатура

ЛЕВОЕ СОЕДИНЕНИЕ

РегистрНакопления.ОстаткиПоСкладам.Остатки( , Склад = &Склад) КАК ОстаткиСКЛ

ПО

ДокТЧ.Номенклатура = ОстаткиСКЛ.Номенклатура

ГДЕ

Ссылка = &Ссылка

Выберем только нужные нам поля:

ВЫБРАТЬ

ДокТЧ.Номенклатура,

ДокТЧ.Количество,

Остатки.КоличествоОстаток,

Остатки.СтоимостьОстаток,

ОстаткиСКЛ.КоличествоОстаток КАК ОстатокНаСкладе

ИЗ

Документ.Расходная.Товары КАК ДокТЧ

ЛЕВОЕ СОЕДИНЕНИЕ

РегистрНакопления.ОстаткиТоваров.Остатки КАК Остатки

ПО

ДокТЧ.Номенклатура = Остатки.Номенклатура

ЛЕВОЕ СОЕДИНЕНИЕ

РегистрНакопления.ОстаткиПоСкладам.Остатки( , Склад = &Склад) КАК ОстаткиСКЛ

ПО

ДокТЧ.Номенклатура = ОстаткиСКЛ.Номенклатура

ГДЕ

Ссылка = &Ссылка

Поля «КоличествоОстаток» и «КоличествоСтоимость» будут использоваться для расчета себестоимости.

Поле «ОстатокНаСкладе» - для проверки наличия нужного количества товара.

Но данный вариант не совсем рационален:

Данные виртуальных таблиц всегда максимально группируются. Т.к. мы присоединяем эти таблицы к несгруппированной табличной части документа, то они дублируются, и приходится повторно вручную (через запрос) их группировать.

Сгруппируем данные табличной части документа до соединения:

Используем механизм «Пакетных» запросов. В виртуальной таблице «Остатки по складам» мы установили отбор по складу. Т.е. сейчас система высчитает остатки всех товаров по этому складу, а уже при соединении таблиц отбросит лишние товары. Это не рационально.

Надо перед соединением таблиц не только сгруппировать ТЧ документа, но и использовать ее данные как фильтр.

Создадим пакетный запрос:

Первый запрос получит таблицу:

Но в сгруппированном виде.

Таблица будет являться источником для соединения полей:

И колонка «Номенклатура» будет являться фильтром для расчета виртуальных таблиц.

Верный запрос:

Выберем из ТЧ первого документа элементы номенклатуры, не являющиеся услугами:

ВЫБРАТЬ

*

ИЗ

Документ.Расходная.Товары

ГДЕ

Ссылка = &Ссылка И НЕ Номенклатура.Услуга

Выберем только необходимые поля и сгруппируем их:

ВЫБРАТЬ

Номенклатура,

СУММА(Количество) КАК Количество

ИЗ

Документ.Расходная.Товары

ГДЕ

Ссылка = &Ссылка И НЕ Номенклатура.Услуга

СГРУППИРОВАТЬ ПО Номенклатура

Эту таблицу поместим во временные, чтобы потом к ней обращаться:

ВЫБРАТЬ

Номенклатура,

СУММА(Количество) КАК Количество

ПОМЕСТИТЬ ДокТЧ

ИЗ

Документ.Расходная.Товары

ГДЕ

Ссылка = &Ссылка И НЕ Номенклатура.Услуга

СГРУППИРОВАТЬ ПО Номенклатура

Через «;» опишем второй запрос, который может в качестве источника использовать таблицу «ДокТЧ»:

ВЫБРАТЬ

Номенклатура,

СУММА(Количество) КАК Количество

ПОМЕСТИТЬ ДокТЧ

ИЗ

Документ.Расходная.Товары

ГДЕ

Ссылка = &Ссылка И НЕ Номенклатура.Услуга

СГРУППИРОВАТЬ ПО Номенклатура

;

ВЫБРАТЬ

*

ИЗ

ДокТЧ КАК ДокТЧ

К полученной таблице присоединяем остатки из регистров:

ВЫБРАТЬ

Номенклатура,

СУММА(Количество) КАК Количество

ПОМЕСТИТЬ ДокТЧ

ИЗ

Документ.Расходная.Товары

ГДЕ

Ссылка = &Ссылка И НЕ Номенклатура.Услуга

СГРУППИРОВАТЬ ПО Номенклатура

;

ВЫБРАТЬ

*

ИЗ

ДокТЧ КАК ДокТЧ

ЛЕВОЕ СОЕДИНЕНИЕ

РегистрНакопления.ОстаткиТоваров.Остатки КАК Остатки

ПО ДокТЧ.Номенклатура = Остатки.Номенклатура

ЛЕВОЕ СОЕДИНЕНИЕ

РегистрНакопления.ОстаткиПоСкладам.Остатки КАК ОстаткиСКЛ

ПО ДокТЧ.Номенклатура = ОстаткиСКЛ.Номенклатура

Данные дублируются из-за того, что есть несколько складов. Поставим ограничение по складу:

ВЫБРАТЬ

Номенклатура,

СУММА(Количество) КАК Количество

ПОМЕСТИТЬ ДокТЧ

ИЗ

Документ.Расходная.Товары

ГДЕ

Ссылка = &Ссылка И НЕ Номенклатура.Услуга

СГРУППИРОВАТЬ ПО Номенклатура

;

ВЫБРАТЬ

*

ИЗ

ДокТЧ КАК ДокТЧ

ЛЕВОЕ СОЕДИНЕНИЕ

РегистрНакопления.ОстаткиТоваров.Остатки КАК Остатки

ПО ДокТЧ.Номенклатура = Остатки.Номенклатура

ЛЕВОЕ СОЕДИНЕНИЕ

РегистрНакопления.ОстаткиПоСкладам.Остатки( , Склад = &Склад) КАК ОстаткиСКЛ

ПО ДокТЧ.Номенклатура = ОстаткиСКЛ.Номенклатура

Выберем только необходимые поля:

ВЫБРАТЬ

Номенклатура,

СУММА(Количество) КАК Количество

ПОМЕСТИТЬ ДокТЧ

ИЗ

Документ.Расходная.Товары

ГДЕ

Ссылка = &Ссылка И НЕ Номенклатура.Услуга

СГРУППИРОВАТЬ ПО Номенклатура

;

ВЫБРАТЬ

ДокТЧ.Номенклатура,

ДокТЧ.Количество,

Остатки.КоличествоОстаток,

Остатки.СтоимостьОстаток,

ОстаткиСКЛ.КоличествоОстаток КАК ОстатокНаСкладе

ИЗ

ДокТЧ КАК ДокТЧ

ЛЕВОЕ СОЕДИНЕНИЕ

РегистрНакопления.ОстаткиТоваров.Остатки КАК Остатки

ПО ДокТЧ.Номенклатура = Остатки.Номенклатура

ЛЕВОЕ СОЕДИНЕНИЕ

РегистрНакопления.ОстаткиПоСкладам.Остатки( , Склад = &Склад) КАК ОстаткиСКЛ

ПО ДокТЧ.Номенклатура = ОстаткиСКЛ.Номенклатура

Оптимизируем запрос. Кроме условия по складу, добавим условие по номенклатуре – отбираем только номенклатуру, которая входит в состав таблицы «ДокТЧ»:

ВЫБРАТЬ

Номенклатура,

СУММА(Количество) КАК Количество

ПОМЕСТИТЬ ДокТЧ

ИЗ

Документ.Расходная.Товары

ГДЕ

Ссылка = &Ссылка И НЕ Номенклатура.Услуга

СГРУППИРОВАТЬ ПО Номенклатура

;

ВЫБРАТЬ

ДокТЧ.Номенклатура,

ДокТЧ.Количество,

Остатки.КоличествоОстаток,

Остатки.СтоимостьОстаток,

ОстаткиСКЛ.КоличествоОстаток КАК ОстатокНаСкладе

ИЗ

ДокТЧ КАК ДокТЧ

ЛЕВОЕ СОЕДИНЕНИЕ

РегистрНакопления.ОстаткиТоваров.Остатки КАК Остатки

ПО ДокТЧ.Номенклатура = Остатки.Номенклатура

ЛЕВОЕ СОЕДИНЕНИЕ

РегистрНакопления.ОстаткиПоСкладам.Остатки( , Склад = &Склад

И Номенклатура В (ВЫБРАТЬ Номенклатура ИЗ ДокТЧ КАК ДокТЧ)) КАК ОстаткиСКЛ

ПО ДокТЧ.Номенклатура = ОстаткиСКЛ.Номенклатура

Запрос формируется намного быстрее, т.к. рассчитываются остатки только по конкретным элементам номенклатуры.

Поставим такое же условие и по первой таблице:

ВЫБРАТЬ

Номенклатура,

СУММА(Количество) КАК Количество

ПОМЕСТИТЬ ДокТЧ

ИЗ

Документ.Расходная.Товары

ГДЕ

Ссылка = &Ссылка И НЕ Номенклатура.Услуга

СГРУППИРОВАТЬ ПО Номенклатура

;

ВЫБРАТЬ

ДокТЧ.Номенклатура,

ДокТЧ.Количество,

Остатки.КоличествоОстаток,

Остатки.СтоимостьОстаток,

ОстаткиСКЛ.КоличествоОстаток КАК ОстатокНаСкладе

ИЗ

ДокТЧ КАК ДокТЧ

ЛЕВОЕ СОЕДИНЕНИЕ

РегистрНакопления.ОстаткиТоваров.Остатки( , Номенклатура В (ВЫБРАТЬ Номенклатура ИЗ ДокТЧ КАК ДокТЧ))

КАК Остатки

ПО ДокТЧ.Номенклатура = Остатки.Номенклатура

ЛЕВОЕ СОЕДИНЕНИЕ

РегистрНакопления.ОстаткиПоСкладам.Остатки( , Склад = &Склад

И Номенклатура В (ВЫБРАТЬ Номенклатура ИЗ ДокТЧ КАК ДокТЧ)) КАК ОстаткиСКЛ

ПО ДокТЧ.Номенклатура = ОстаткиСКЛ.Номенклатура

Добавим условие на «МоментВремени» и присоединяемые поля опишем с функцией «ЕСТЬNULL», иначе они могут не присоединиться:

ВЫБРАТЬ

Номенклатура,

СУММА(Количество) КАК Количество

ПОМЕСТИТЬ ДокТЧ

ИЗ

Документ.Расходная.Товары

ГДЕ

Ссылка = &Ссылка И НЕ Номенклатура.Услуга

СГРУППИРОВАТЬ ПО Номенклатура

;

ВЫБРАТЬ

ДокТЧ.Номенклатура,

ДокТЧ.Количество,

ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК КоличествоОстаток,

ЕСТЬNULL(Остатки.СтоимостьОстаток, 0) КАК СтоимостьОстаток,

ЕСТЬNULL(ОстаткиСКЛ.КоличествоОстаток, 0) КАК ОстатокНаСкладе

ИЗ

ДокТЧ КАК ДокТЧ

ЛЕВОЕ СОЕДИНЕНИЕ

РегистрНакопления.ОстаткиТоваров.Остатки(&МоментВремени, Номенклатура В (ВЫБРАТЬ Номенклатура ИЗ ДокТЧ КАК ДокТЧ)) КАК Остатки

ПО ДокТЧ.Номенклатура = Остатки.Номенклатура

ЛЕВОЕ СОЕДИНЕНИЕ

РегистрНакопления.ОстаткиПоСкладам.Остатки(&МоментВремени, Склад = &Склад

И Номенклатура В (ВЫБРАТЬ Номенклатура ИЗ ДокТЧ КАК ДокТЧ)) КАК ОстаткиСКЛ

ПО ДокТЧ.Номенклатура = ОстаткиСКЛ.Номенклатура

Теперь перенесем запрос в документ «Расходная»:

При копировании запроса не вставляются знаки «Перенос строки». Их можно добавить:

«Текст – Блок – Добавить перенос строки»

Если надо сохранять временную таблицу, то используется «Менеджер временных таблиц» - объект, хранящий временные таблицы. Данный объект присваивается запросу. После этого можно выполнять другие действия, не связанные с этим запросом. Можно передать в другой запрос, другую процедуру или функцию переменную менеджера временных таблиц. Если другому запросу присвоить менеджер, то там можно использовать таблицу предыдущего запроса.

Итого код процедуры проведения:

Процедура ОбработкаПроведения(Отказ, РежимПроведения)

Движения.ОстаткиТоваров.Записывать = Истина;

Движения.ОстаткиПоСкладам.Записывать = Истина;

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Номенклатура,

| СУММА(Количество) КАК Количество,

| МИНИМУМ(НомерСтроки) КАК НомерСтроки

|ПОМЕСТИТЬ ДокТЧ

|ИЗ

| Документ.Расходная.Товары

|ГДЕ

| Ссылка = &Ссылка И НЕ Номенклатура.Услуга

|СГРУППИРОВАТЬ ПО Номенклатура

|;

|ВЫБРАТЬ

| ДокТЧ.НомерСтроки,

| ДокТЧ.Номенклатура,

| ДокТЧ.Количество,

| ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК КоличествоОстаток,

| ЕСТЬNULL(Остатки.СтоимостьОстаток, 0) КАК СтоимостьОстаток,

| ЕСТЬNULL(ОстаткиСКЛ.КоличествоОстаток, 0) КАК ОстатокНаСкладе

|ИЗ

| ДокТЧ КАК ДокТЧ

|ЛЕВОЕ СОЕДИНЕНИЕ

| РегистрНакопления.ОстаткиТоваров.Остатки(&МоментВремени, Номенклатура В (ВЫБРАТЬ Номенклатура ИЗ ДокТЧ

КАК ДокТЧ)) КАК Остатки

|ПО ДокТЧ.Номенклатура = Остатки.Номенклатура

|ЛЕВОЕ СОЕДИНЕНИЕ

| РегистрНакопления.ОстаткиПоСкладам.Остатки(&МоментВремени, Склад = &Склад

| И Номенклатура В (ВЫБРАТЬ Номенклатура ИЗ ДокТЧ КАК ДокТЧ)) КАК ОстаткиСКЛ

|ПО ДокТЧ.Номенклатура = ОстаткиСКЛ.Номенклатура";

Запрос.УстановитьПараметр("МоментВремени", МоментВремени());

Запрос.УстановитьПараметр("Ссылка", Ссылка);

Запрос.УстановитьПараметр("Склад", Склад);

Результат = Запрос.Выполнить();

Выборка = Результат.Выбрать();

Пока Выборка.Следующий() Цикл

Если Выборка.Количество > Выборка.ОстатокНаСкладе Тогда

Сообщение = Новый СообщениеПользователю;

Сообщение.Текст = "Не хватает товара """ + Выборка.Номенклатура + """ из необходимых "

+ Выборка.Количество +

" в наличии осталось только " + Выборка.ОстатокНаСкладе;

Сообщение.Поле = "Товары[" + (Выборка.НомерСтроки - 1) + "].Количество";

Сообщение.УстановитьДанные(ЭтотОбъект);

Сообщение.Сообщить();

Отказ = Истина;

Движения.ОстаткиТоваров.Записывать = Ложь;

Движения.ОстаткиПоСкладам.Записывать = Ложь;

КонецЕсли;

Если Отказ Тогда

Продолжить;

КонецЕсли;

Движение = Движения.ОстаткиТоваров.ДобавитьРасход();

Движение.Период = Дата;

Движение.Номенклатура = Выборка.Номенклатура;

Движение.Количество = Выборка.Количество;

Движение.Стоимость = Выборка.Количество / Выборка.КоличествоОстаток * Выборка.СтоимостьОстаток;

Движение = Движения.ОстаткиПоСкладам.ДобавитьРасход();

Движение.Период = Дата;

Движение.Номенклатура = Выборка.Номенклатура;

Движение.Количество = Выборка.Количество;

Движение.Склад = Склад;

КонецЦикла;

КонецПроцедуры

В режиме исполнения:

Нажимаем «ОК».

Дата первого документа раньше, чем дата приходного документа, в котором на склад «Шушары» пришли ручки и карандаши:

А дата второго документа позже, поэтому документ провелся.

Посмотрим в отчете остатки по складам:

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

Продадим все ручки:

И посмотрим отчет остатков на складах: