d9e5a92d

Конфигурирование в системе " 1С:Предприятие 8.0 ". Решение оперативных задач

3.4. Организация партионного учета

Ранее мы использовали средневзвешенный способ списания себестоимости.

Рассмотрим более подробно, как он работал.

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

При списании же какого-то количества товара (см. модуль проведения расходной накладной) определяется себестоимость единицы товара из регистра делением общего остатка по стоимости на общий остаток по сумме.



Если в один день требуется продать часть товара и оприходовать еще партию товара, то может сложиться следующая картина.

Движения



Товар

Количество

Стоимость

+

Яблоки

10

100

+

Яблоки

8

70

+

Яблоки

5

80

Остаток



Товар

Количество

Стоимость

Яблоки

23

250

Себестоимость 1 яблока = 250/23 = 10,87

Рис. 1Л 3. В списании участвуют три прихода яблок.

На рис. 1.13 Представлен вариант, когда сначала провели новую приходную накладную, а на рис.1.14 - сначала провели расходную накладную. Хотя реально продавалось и в одном и в другом случае одно и то же яблоко!

52



Технологии проведения документов

Движения



Товар

Количество

Стоимость

+

Яблоки

10

100

+

Яблоки

8

70

Остаток



Товар

Количество

Стоимость

Яблоки

18

170

Себестоимость 1 яблока = 170/18 = 9.44

Рис. 1.14. В списании участвуют только два прихода яблок.

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

Более точно можно было бы списывать себестоимость, если не перемешивать все партии товаров на складе (а при хранении остатков на одном измерении Товар именно это и происходит), а хранить партии одного и того же товара отдельно.

Для этого нам понадобится еще одно измерение ПАРТИЯ.

Движения



Товар

Партия

Количество

Стоимость

+

Яблоки

1

10

100

+

Яблоки

2

8

70

+

Яблоки

5

80

Остаток



Товар

Партия

Количество

Стоимость

Яблоки

1

10

100

Яблоки

2

8

70

Яблоки

3

5

80

Себестоимость 1 яблока из партии "1" - 100/10 = 10

Рис. 1.15. Хранение яблок по партиям.

В результате, сколько бы потом не было приходов, но при списании яблока из партии "1" списываться будет именно себестоимость этой партии.

53



Конфигурирование в системе "1С:Предприятие 8.0". Решение оперативных задач

Итак, в регистр ОстаткиНоменклатуры добавляем измерение Партия.

Конфигурирование в системе


Как показывает практика, оптимальным типом для этого измерения является ДокументСсылка. И вписываться туда должен именно тот документ, по которому пришла эта партия (еще говорят -партиеобразующий документ).

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

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

54





Конфигурирование в системе


Технологии проведения документов

Переходим к изменению проведения документов.

В процедуре ОбработкаПроведения() приходной накладной в блоке формирования движения по регистру остаткиНоменклатуры добавляем еще одну строчку;

Движение = Движения. ОстаткиНоменклатуры.Добавить();

Движение.ВидДвижения = ВидДвиженияНакопления.Приход;

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

Движение. Регистратор = Ссылка;

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

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

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

//**

Движение.Партия = Ссылка;

А вот в случае проведения расходной накладной - тут несколько сложнее.

Разберемся, что потребуется сделать при проведении.



Конфигурирование в системе "1С:Предприятие 8.0 ". Решение оперативных задач

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

Далее выбрать остатки всех партий каждого товара. Причем эти партии должны быть упорядочены в зависимости от того, каким образом мы будем списывать партии: или в порядке возрастания дат прихода партий (метод называется FIFO), или в порядке убывания (метод называется LIFO).

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

Кроме того, необходимо будет вовремя остановиться в процессе списания партий, т.е. постоянно помнить, сколько осталось досписать товара.

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

То есть для расходной накладной такого вида

Конфигурирование в системе


Для проведения хотелось бы получить исходную таблицу что-то вроде такой:

Конфигурирование в системе


56



Технологии проведения документов

Заметьте, табличка явно с группировками. На верхнем уровне (по товарам) надо видеть: сколько всего товара на складе, сколько отпускаем.

На нижнем (по партиям) надо будет видеть, сколько товара, и на какую сумму находится в остатке по каждой партии. Чтобы организовать правильное списание по партиям.

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



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

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

Запрос.Текст = "ВЫБРАТЬ

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

Ост.Партия КАК Партия,

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

Ост.СуммаОстаток КАК СуммаОст,

Накл.Количество КАК КолДок,

Накл.Сумма КАК СуммаДок

ИЗ (ВЫБРАТЬ

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

Сумма{Док.Количество) КАК Количество,

Сумма(Док.Сумма) КАК Сумма ИЗ Документ.Расходная.Товары КАК Док ГДЕ Док.Ссылка = ПарСсылка СГРУППИРОВАТЬ ПО Док.Номенклатура) как Накл

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

РегистрНакопления.ОстаткиНоменклатуры.Остатки(Момент, Номенклатура В (ВЫБРАТЬ РАЗЛИЧНЫЕ Док.Номенклатура ИЗ Документ.Расходная.Товары КАК Док ГДЕ Док.Ссылка = ПарСсылка)

)как Ост ПО Накл.Номенклатура = Ост. Номенклатура

//1

112

//3

//4







Если Режим = РежимПроведенPяДокумента.Оперативный Тогда Запрос.Текст = Запрос.Текст +" ИЗМЕНЕНИЯ

РегистрНакопления.ОстаткиНоменклатуры.Остатки

115



57



Конфигурирование в системе " 1С:Предприятие 8.0". Решение оперативных задач



КонецЕсли;

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

[УПОРЯДОЧИТЬ ПО

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

| Ост.Партия.Дата ВОЗР

|ИТОГИ

Сумма(КолОст),

Сумма(СуммаОст),

Максимум(КолДок), j Максимум(СуммаДок) |ПО Накл.Номенклатура, Ост.Партия

//6

//7







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

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

//8

119



ВыборкаТоваров -

РезультатЗапроса.Выбрать(ОбходРезультатаЗагтроса.ПоГруппировкам, "Номенклатура");

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

//Контроль нехватки //11

Остаток = ?(ВыборкаТоваров.КолОст = Null,0,ВыборкаТоваров.КолОст); КолДок = ?(ВыборкаТоваров.КолДок = Null,0,ВыборкаТоваров.КолДок); СуммаДок = ?(ВыборкаТоваров.СуммаДок = Null,0,ВыборкаТоваров.СуммаДок);

Нехватка = КолДок - Остаток; Если Нехватка0 Тогда

Сообщить("Нехватка товара " + СокрЛП(ВыборкаТоваров.Номенклатура) + ": " + Нехватка);

Сообщить("Расходная " + Номер+ " от " +Дата+" не проводится!"); Отказ = Истина; КонецЕсли;



// списание партий НадоСписать = КолДок;

//12







ВыборкаПартий "Партия");

ВыборкаТоваров.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам,



58



Технологии проведения документов

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

КолПартии = ?(Вы6оркаПартий.КолОст = Null, 0, ВыборкаПартий.КолОст); //13

СуммаПартии = ?(ВыборкаПартий.СуммаОст = Null, О,

ВыборкаПартий.СуммаОст);

//Вычисление количества списания и себестоимости Если НадоСписатьКолПартии Тогда

//списываем часть партии

КоличествоСп = НадоСписать;

СебестоимостьСп = СуммаПартии/КолПартии*КоличествоСп;

НадоСписать = 0; Иначе

//списываем всю партию

КоличествоСп = КолПартии;

СебестоимостьСп = СуммаПартии;

НадоСписать =НадоСписать-КолПартии; КонецЕсли;

//по регистру "ОстаткиНоменклатуры" //14

Движение - Движения.ОстаткиНоменклатуры.ДобавитьРасход();

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

Движение. Регистратор = Ссылка;

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

Движение. Партия = ВыборкаПартий.Партия;

Движение.Количество = КоличествоСп;

Движение.Сумма = СебестоимостьСп;

Если НадоСписать=0 Тогда //15

Прервать; КонецЕсли;

КонецЦикла;

//по регистру "Продажи"

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

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

Движение.Регистратор = Ссылка;

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

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

Движение.Количество = КолДок;

59



Конфигурирование в системе "1С:Предприятие 8.0". Решение оперативных задач

Движение.Сумма = СуммаДок; КонецЦикла;

// по регистру "Задолженности"

Движение = Движения.Задолженности.ДобавитьПриход{):

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

Движение. Регистратор = Ссылка;

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

Движение.Долг = СуммаДокумента;

Движения.ОстаткиНоменклатуры.Записать(); Движения. Продаж.Записать(); Движения.3адолженности.3аписать();

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

Комментарий к тексту процедуры:

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

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

//3 Для получения данных об остатках номенклатуры в выходной таблице используем левое внешнее соединение с таблицей остатков регистра ОстаткиНоменклатуры по Номенклатуре. Причем при получении данных из регистра указываем, что будем пользоваться параметрами для позиционирования по времени и по требуемым товарам. Чтобы определиться, по каким именно товарам - опять используем вложенный запрос.

//4 Обратите внимание, во вложенном запросе мы используем контрукцию ВЫБРАТЬ РАЗЛИЧНЫЕ- Если этого не сделать, то при наличии дублей строк мы бы рисковали задвоением или даже

60



Технологии проведения документов

затроением информации об остатках. Система бы вытаскивала записи из регистра для каждого упоминания товара в табличной части.

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

//6 Упорядочиваем выходную таблицу - готовим ее под FIFO -списание.

//7 Указываем, по каким полям будем подсчитывать итоги выходной таблицы запроса. Здесь сталкиваемся вот с какой сложностью. Поля КолДок и СуммаДок будут заполнены для всех исходных записей количеством и суммой из документа для каждой товарной позиции. Но исходной записью является запись уровня Партия. То есть, если применить функцию Сумма() в итогах, то при наличии, например, двух партий - получим на уровне группировки Номенклатура задвоенные КолДоки СуммаДок. А нам нужно, чтобы в этой ситуации эта информация не суммировалась, а просто перенеслась с уровня исходных записей. Выходим из положения, применив функцию Максимум(). Поскольку все значения КолДок и СуммаДок в исходных записях - одинаковы (это мы обеспечили выше - борясь с дублями строк посредством вложенных запросов).

//8 Устанавливаем значения для параметров запроса. //9 Выполняем запрос.

//10 Открываем цикл обхода результатов запроса по верхней группировке (по Номенклатуре)

//11 Определяем,хватает ли товара в регистре для данной строки документа. Если не хватает, обязательно предупреждаем пользователя, почему и какой документ нельзя провести.

//12 Открываем вложенный цикл перебора строк партий по данному товару.

//13 Вычисляем, сколько надо списать по количеству и деньгам при ситуациях, когда партия уходит целиком или частично.

//14 Заполняем атрибуты регистра для формирования очередной записи (по данной партии)

//15 Проверяем, не пора ли закончить перебирать партии. Может, все что требовалось - уже списали.



Конфигурирование в системе " 1С:Предприятие 8.0". Решение оперативных задач

Практикум №10

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

3.5. Правила внесения изменений в структуру регистров живой базы

Как показывает практика, большинство ошибок программистов возникает именно при внесении изменений в живые, то есть работающие, базы. Посему давайте обобщим этапы проделанных нами операций в небольшой свод правил.

Итак, вносить изменения, затрагивающие структуру регистров, необходимо в следующей очередности:

  1. Продумать все детали механизма, который Вы собираетесь

    построить (Какие структурные изменения будут в регистре

    (регистрах), кто будет делать +-движения, кто будет делать --

    движения?)
  2. Внести структурные изменения в регистр (регистры).

В системе 1С:Предприятие 8.0 изменение структуры регистров не потребует для обеспечения правильности синтаксиса изменения текстов программных модулей, читающих данные из регистров. Однако это может отразиться на скорости их исполнения, поскольку к данным первых измерений доступ осуществляется быстрее, чем к данным последних.

  1. Прописать положительные движения по этому регистру

    (регистрам).
  2. Отладить написанный алгоритм проведения на проведении

    одного документа (но для каждого вида документов, которые делают

    +-движения) при различных вариантах исходных данUых.
  3. Прописать отрицательные движения по этому регистру

    (регистрам).

Конечно, если это требуется. Регистры сведений и оборотные регистры не обладают свойством ВидДвижения. Но и тут могут применяться строно-записи для оборотного регистра (например, учет возвратов в продажах).

62



Технологии проведения документов

  1. Отладить прописанное на проведении одного документа(но для

    каждого вида документов, которые делают --движения) при

    различных исходных данных.
  2. Убедиться в корректности работы всех механизмов, которые

    базируются на этом регистре (регистрах) - то есть корректность

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

Как же это сделать? Ведь конфигурация может быть и огромной! Лучше всего на панели инструментов Конфигурация ( наверху)

нажать кнопку (

Конфигурирование в системе


) -Поиск во всех текстах. В полученном окне проставить условия поиска следующим образом:

Конфигурирование в системе


Когда поиск выполнится - внизу на табло появятся строки со всеми упоминаниями мест, где в системе встречается строчка с заголовком нашего регистра. А теперь открывайте все эти модули, таблицы и диалоги - и разбирайтесь, корректно будет это работать или нет.

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

8) Перепроведите все документы, связанные с данным регистром.

Чтобы не получилось, что половина накладных по старым законам проведена (по старому алгоритму проведения), половина - по новым, а какие как - непонятно.

Делается это достаточно просто - системной обработкой Проведение документов. Например, так:



Конфигурирование в системе "1С:Предприятие 8.0". Решение оперативных задач

Конфигурирование в системе


Правила эти очень просты. Вероятно, большинство программистов в системе 1С:Предприятие именно так и работают. И большинство из них имеют силу воли все описанное в этой главе пунктуально выполнять. И проблем тогда не имеют.

Так что не попадайте в разряд меньшинств!

64



Технологии проведения документов

3.6. Алгоритм реализации сложного проведения документов в системе 1С:Предприятие 8.0

Поставим себе следующую сложную (но, увы, далеко не самую сложную) задачу на проведение документа.

Движения по регистрам остаются прежними: Остается контроль свободного остатка; остается партионный учет, организованный по принципу FIFO; остается проведение по регистру ПродажиТоваров.

Но в дополнение:

Ну, можно было бы еще навернуть какие-нибудь квоты по покупкам, накопительные скидки и т.д., но - пока хватит.

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

Логически выйдем на него.

Какой бы сложности проведение ни понадобилось, документ всегда останется документом. У него есть шапка, и есть табличная часть (табличные части).

Как правило, в зависимости от состояния реквизитов шапки (и еще чего-либо) по некоторым регистрам документ будет проводиться, а по некоторым - нет.

Какими бы сложными ни были условия проведения документа (отказа в проведении), они чаще всего будут касаться реквизитов шапки и реквизитов табличных частей (и еще чего-то).

Самый быстрый способ получения данных в системе 1С:Предприятие 8.0 - опираясь на их табличное представление, то есть через запрос.



Конфигурирование в системе "1С:Предприятие 8.0". Решение оперативных задач

Таким образом, определяем следующую структуру универсального алгоритма проведения

В качестве типового для случая работы с единственной табличной частью документа можно считать следующий текст процедуры Обработка Проведения():

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

//структура, содержащая имена регистров, по которым надо проводить документ Перем СтруктураПроведенияПоРегистрам;

//*1*

// Добудем нужные реквизиты по шапке запросом

РезультатЗапроса По Шапке = СформироватьЗапросПоШапке(Режим);

// Получим реквизиты шапки из запроса

ВыборкаПоШапкеДокумента = РезультатЗапросаПоШапке.Выбрать(); Если ВыборкаПоШапкеДокумента.СледуюшиЙ() Тогда

//*2*

// Создадим и заполним структуры, содержащие имена регистров,

// по которым в зависимости от вида операции будет проводиться документ.

// В дальнейшем будем считать, что если для регистра не создан ключ в структуре,

// то проводить по нему не надо.

ЗаполнитьСтруктуруПроведенияПоРегистрам(СтруктураПроведенияПоРегистрам,



Технологии проведения документов

ВыборкаПоШапкеДокумента);

//*3*

//Проверим заполнение реквизитов шапки и возможность проведения ПроверитьЗаполнениеШапки(ВыборкаПоШапкеДокумента, Отказ); КонтрольВозможностиПроведенияПоШапке(ВыборкаПоШапкеДокумента, Отказ);

//*4*

// Сформируем структуру параметров проведения по шапке документа,

// чтобы не рассчитывать их для каждого движения

СтруктураПараметров = Новый Структура();

// определяем значения параметров,

// можно через функцию; можно, передавая выборку по шапке документа

СтруктураПараметров.Вставить("ПараметрК",

ОпределитьЗначениеПарметраК(Режим,ВыборкаПоШапкеДокумента));

//•5*

// Сформируем движения по шапке документа

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

ДвиженияПоРегистрамПоШапке(ВыборкаПоШапке Документа,

СтруктураПроведенияПоРегистрам, СтруктураПараметров); КонецЕсли;

//*6*

// Добудем нужные реквизиты по строкам табличной части запросом РезультатЗапросаПоСтрокам = СформироватьЗапросПоСтрокамДокумента(Режим,

ВыборкаПоШапкеДокумента);

// В цикле по строкам табличной части будем добавлять // информацию в движения документа ВыборкаПоСтрокам Документа =

РезультатЗапросаПоСтрокам.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);

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

//*7*

//Проверим заполнение реквизитов табличной части и возможность проведения

ПроверитьЗаполнениеСтрокиТаблЧасти(ВыборкаПоСтрокамДокумента, Отказ);

КонтрольВозможностиПроведенияСтрокиТаблЧасти(

В ыборкаПоСтрокамДокумента, Отказ);

67



Конфигурирование в системе "IС:Предприятие 8.0". Решение оперативных задач

II Сформируем движения по строке документа Если Не Отказ Тогда

ДвиженияПоРегистрамПоСтрокеДокумента(ВыборкаПоСтрокамДокумента, ВыборкаПоШапкеДокумента, СтруктураПроведения По Регистрам, СтруктураПараметров);

КонецЕсли;

КонецЦикла;

//*9*

// Запишем движения по регистрам

Для каждого ТекДвиж Из Движения Цикл

Если ТекДвиж.Количество() 0 Тогда

ТекДвиж.ЗаписатьО;

КонецЕсли; КонецЦикла;

КонецЕсли; КонецПроцедуры

Как видите, процедура - это каркас, который вызывает вспомогательные функции или передает управление другим процедурам в нужный момент.

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

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

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

Вернемся же к нашей задаче.

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

Добавьте в справочник Контрагенты реквизит

СобственноеЮрЛицо, тип- Булево.

68





Конфигурирование в системе


Технологии проведения документов

Организуйте самостоятельно на форме элемента справочника возможность его заполнения.

Теперь меняем процедуру ОбработкаПроведения() документа Расходная на вышеприведенную в данной главе.

Остается дописать вызываемые из нее функции и процедуры.

Сформируем запрос по шапке.

Какие данные надо в него включить? Анализируем содержание задачи.

Надо проводить документ по регистру Задолженности - значит, как минимум в запросе должны быть: Ссылка, Дата, Контрагент, СуммаДок.

Надо будет контролировать - не задолжал ли покупатель, значит, в запросе понадобится еще сумма долга по данному контрагенту из регистра Задолженности, рассчитанная на момент времени документа.

Надо будет определить - не является ли покупатель собственным юр. лицом - значит нужно соответствующее поле в запросе по шапке.

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

// Формируем запрос по шапке документа и по неободимым данным регистров.



Конфигурирование в системе '1С:Предприятие 8.0 ". Решение оперативных задач

Функция СформироватьЗапросПоШапке(Режим) Запрос = Новый Запрос; Запрос.Текст = "ВЫБРАТЬ

Расходная.Ссылка,

Расходная. Дата,

J Расходная.Контрагент,

| Расходная.Контрагент.СобственноеЮрЛиыо как СобственноеЮрЛиио,

| Расходная. СуммаДокумента,

| ЗадолженностиОстатки.ДолгОстаток

|ИЗ

Документ.Расходная КАК Расходная [ЛЕВОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ

РегистрНакопления.Задолженности.Остатки(Момент,) КАК ЗадолженностиОстатки |ПО

| Расходная.Контрагент = ЗадолженностиОстатки.Контрагент |ГДЕ

Расходная. Ссылка = ПарСсылка

Если Режим = Режим ПроведенияДокумента. Оперативный Тогда

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

|ДЛЯ ИЗМЕНЕНИЯ

| РегистрНакопления.Задолженности.Остатки

КонецЕсли;

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

Возврат Запрос.Выполнить(); КонецФункции

Определение структуры проведения по регистрам

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

Процедура ЗаполнитьСтруктуруПроведенияПоРегистрам(

СтруктураПроведенияПоРегистрам, Вы боркаПоШапкеДокумента)

70



Технологии проведения документов

СтруктураПроведенияПоРегистрам = Новый Структура();

СтруктураПроведенияПоРегистрам.Вставить("Задолженности"); СтруктураПроведенияПоРегистрам.Вставить("ОстаткиНоменклатуры"); Свой = ВыборкаПоШапкеДокумента.СобственноеЮрЛицо; Свой = ?(Свой = Null, Ложь, Свой); Если Не Свой Тогда

СтруктураПроведенияПоРегистрам.Вставить(" Продажи"); КонецЕсли;

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

Проверка заполнения реквизитов шапки и условий возможности проведения

Процедура ПроверитьЗаполнениеШапки(ВыборкаПоШапкеДокумента, Отказ) Если ВыборкаПоШапкеДокумента. Контрагент = Null Тогда Сообщить("Не указан Контрагент");

Сообщить("Расходная " + Номер+ " от " +Дата+" не проводится!"); Отказ = Истина; КонецЕсли; КонецПроцедуры

Процедура КонтрольВозможностиПроведенияПоШапке(

ВыборкаПоШапкеДокумента, Отказ) Если ВыборкаПоШапкеДокумента.ДолгОстаток о Null Тогда

Если ВыборкаПоШапкеДокумента.ДолгОстаток 0 Тогда

Сообщить("Контрагент "+ ВыборкаПоШапкеДокумента.Контрагент + " еше должен "+ВыборкаПоШапкеДокумента.ДолгОстаток);

Сообщить("Расходная " + Номер+ " от " +Дата+" не проводится!");

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

КонецЕсли;

КонецЕсли;

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

Формирование структуры параметров проведения

Этот параметр потом понадобится при формировании по каждой строке документа для регистра Продажи.

71



Конфигурирование в системе "1С:Предприятие 8.0". Решение оперативных задач

Функция ОпределитьЗначениеПараметраК(Режим, ВыборкаПоШапкеДокумента) //в данном случае - это контрагент Если ВыборкаПоШапкеДокумента-Koнтpaгeнт Null Тогда

Возврат ВыборкаПоШапкеДокумента.Контрагент; КонецЕсли;

Возврат Справочники.Контрагенты.ПустаяСсылка(); КонецФункиии

Формирование движений по шапке документа

Обратите внимание, сначала убеждаемся, что по данному регистру надо формировать движения.

Процедура ДвиженияПоРегистрамПоШапке(ВыборкаПоШапкеДокумента, СтруктураПроведенияПоРегистрам, СтруктураПараметров)

Если СтруктураПроведенияПоРегистрам.Свойство("Задолженности") Тогда // по регистру "Задолженности"

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

Движение.Период = ВыборкаПоШапкеДокумента.Дата;

Движение. Регистратор = ВыборкаПоШапкеДокумента.Ссылка;

//измерения

Движение.Контрагент = ВыборкаПоШапкеДокумента.Контрагент;

//ресурсы

Движение.Долг = ВыборкаПоШапкеДокумента.СуммаДокумента;

//реквизиты

Движение.СобственноеЮрЛицо = СтруктураПараметров.ПараметрК; КонецЕсли;

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

Запрос по табличной части с получением данных из других объектов

Аналогично, как и в случае с запросом по шапке, определяемся, какие данные нам понадобятся для формирования движений по регистрам и выполнения всех условий.

Функция СформироватьЗапросПоСтрокамДокумента(Режим, ВыборкаПоШапкеДокумента) Запрос = Новый Запрос; Запрос.Текст = "ВЫБРАТЬ

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

72



Технологии проведения документов

Ост.Партия КАК Партия, Ост.КоличествоОстаток КАК КолОст, Ост.СуммаОстаток КАК СуммаОст, Накл. Количество КАК КолДок, Накл.Сумма КАК СуммаДок

ИЗ (ВЫБРАТЬ

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

Сумма(Док.Количество) КАК Количество,

Сумма(Док.Сумма) КАК Сумма ИЗ Документ.Расходная.Товары КАК Док ГДЕ Док.Ссылка = ПарСсылка СГРУППИРОВАТЬ ПО Док.Номенклатура) как Накл

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

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

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

| ГДЕ Док.Ссылка = ПарСсылка)

| )как Ост

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

|";

Если Режим = РежимПровеленияДокумента.Оперативный Тогда

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

|ДЛЯ ИЗМЕНЕНИЯ

| РегистрНакопления.ОстаткиНоменклатуры.Остатки

I";

КонецЕсли;

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

|УПОРЯДОЧИТЬ ПО

| Накл. Номенклатура, Ост, Партия.Дата возр //реализовали FIFO

|ИТОГИ ПО

|Накл.Номенклатура, Ост.Партия

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

73



Конфигурирование в системе "1С:Предприятие 8.0". Решение оперативных задач

Возврат Запрос. Выполнить(); КонецФункции

Проверка заполнения реквизитов в строке табличной части и условий возможности проведения

Процедура ПроверитьЗаполнениеСтрокиТаблЧасти(ВыборкаПоСтрокамДокумента, Отказ) Если ВыборкаПоСтрокамДокумента.Номенклатура = Null Тогда

Сообщить("Документ содержит строки с пустой номенклатурной позицией"); Сообщить("Расходная " + Номер+ " от" +Дата+" не проводится!"); Отказ = Истина; Иначе

Если ВыборкаПоСтрокамДокумента.КолДок = Null Тогда

Сообшить("Для товара "+Выбор каПоСтрокам Доку мента. Ном енклатура+

" указано нулевое количество!");

Сообшить("Расходная " + Номер+ " от " +Дата+" не проводится!"); Отказ = Истина; КонеиЕсли; КонецЕсли; КонецПроцедуры

Процедура КонтрольВозможностиПроведенияСтрокиТаблЧасти(

ВыборкаПоСтрокамДокумента, Отказ) //Контроль нехватки Остаток = ?(ВыборкаПоСтрокамДокумента.КолОст = Null,

0,В ыборкаПоСтрокамДокумента. КолОст); Нехватка = В ыборкаПоСтрокамДокумента.КолДок - Остаток; Если Нехватка0 Тогда

Сообщить("Hexватка товара " +

СокрЛП(ВыборкаПоСтрокамДокумента. Номенклатура) + ": " + Нехватка);

Сообшить("Расходная " + Номер+ " от" +Дата+" не проводится!");

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

КонецЕсли;

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

Формирование движений по строке табличной части

Тут кроме непосредственного формирования движений реализуем партионный учет:

74



Технологии проведения документов

Процедура ДвиженияПоРегистрамПоСтрокеДокумента(ВыборкаПоСтрокамДокумента, ВыборкаЛоШапкеДокумента,СтруктураПроведенияПоРегистрам, СтруктураПараметров)

Если СтруктураПроведенияПоРегистрам.Свойство("ОстаткиНоменклатуры") Тогда // списание партий

НадоСписать = ВыборкаПоСтрокамДокумента.КолДок; ВыборкаПартий = ВыборкаПоСтрокамДокумента.Выбрать(

ОбходРезультатаЗапроса.ПоГруппировкам, "Партия"); Пока ВыборкаПартий. Следующий() Цикл

КолПартии = ?(ВыборкаПартий.КолОст = Null, 0, ВыборкаПартий.КолОст); СуммаПартии = ?(ВыборкаПартий.СуммаОст = Null,

0, ВыборкаПартий.СуммаОст);

//Вычисление количества списания и себестоимости Если НадоСписать КолПартии Тогда

//списываем часть партии

КоличествоСп = НадоСписать;

СебестоимостьСп = СуммаПартии/КолПартии*КоличествоСп;

НадоСписать = 0; Иначе

//списываем всю партию

КоличествоСп ~ КолПартии;

СебестоимостьСп = СуммаПартии;

НадоСписать =НадоСписать-КолПартии; КонецЕсли;

//по регистру "ОстаткиНоменклатуры"

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

Движение. Период = ВыборкаПоШапкеДокумента.Дата;

Движение. Регистратор = ВыборкаПоШапкеДокумента. Ссылка;

//измерения

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

Движение.Партия = ВыборкаПартий. Партия;

//ресурсы

Движение. Количество = КоличествоСп;

Движение. Сумма = СебестоимостьСп;

Если НадоСписать = 0 Тогда

Прервать;

75



Конфигурирование в системе "1С:Предприятие 8.0". Решение оперативных задач

КонецЕсли;

КонецЦикла; КонецЕсли;

Если СтруктураПроведенияПоРегистрам.Свойство("Продажи") Тогда

//по регистру "Продажи"

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

Движение. Период = ВыборкаПоШапкеДокумента.Дата;

Движение.Регистратор = ВыборкаПоШапкеДокумента.Ссылка;

//измерения

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

Движение. Контрагент = СтруктураП араметров.ПараметрК;

//ресурсы

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

Движение.Сумма = ВыборкаПоСтрокамДокумента.СуммаДок; КонецЕсли;

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

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

А самое большое достоинство данного подхода, что постановщики задачи могут практически до бесконечности усложнять проведение документа, однако это не усложнит технологичность механизма проведения.

Практикум №11

Для тренировки и контроля усвоения материала опять же — учитываем начичие регистра БлокировкаТовара. Количество заблокированного товара должно увеличивать нехватку при оперативном проведении документа.

Кроме того, необходимо дать возможность пользователю самому выбирать, как организовать списание партий: по FIFO (списывать, начиная с самых старых) или по LIFO (списывать, начиная с самых свежих). Поскольку принцип списания принимается в учетной политике предприятия сроком на год, необходимо организовать хранение его значения на регистре сведений УчетнаяПолитика (без измерений и с периодичностью год). При проведении документа -разумеется, надо опираться на это значение.

76



4. Решение задач анализа показателей движения. Использование реквизитов регистра остатков и оборотных регистров

4.1. Отчет Анализ продаж запрос - построение запросом по документам

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

То есть, нужен отчет такого типа:

Конфигурирование в системе




Можем ли мы построить его, основываясь на существующих данных конфигурации? Можем.

Для этого требуется каким-то образом сгруппировать по товарам данные о продажах текущего периода, прошлого периода и текущего остатка товара. Данные о продажах прошлого и текущего периодов можно получить запросами по документу Расходная, данные об остатке товара - запросом по регистру ОстаткиНоменклатуры.

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

отчет

Строим посредством конструктора выходных форм АнализПродажПоДок.

Первый запрос строим по табличной части Товары документа Расходная.

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





77



Конфигурирование в системе "1С:Предприятие 8.0", Решение оперативных задач

Конфигурирование в системе


Теперь группируем информацию:

Конфигурирование в системе


78



Решение задач анализа показателей движения. Использование реквизитов

регистра остатков и оборотных регистров

Указываем условие, по которому, собственно, и определяем, что данные в первом запросе нужно получать за некий текущий интервал. И, кроме того, необходимо собирать данные только по проведенным документам.

Конфигурирование в системе


Теперь на закладке Объединения/Псевдонимы можем поменять имена полей выходной таблицы и добавить следующий запрос, нажав соответствующую кнопку или клавишу Ins:

79



Конфигурирование в системе "1С:Предприятие 8.0". Решение оперативных задач

Конфигурирование в системе


Запрос2 формируем аналогично первому:

Конфигурирование в системе


Группировка - аналогично группированию, как в Запрос1.

А вот условие будет по другому интервалу, от ДатаН2 до ДатаК2



Конфигурирование в системе


Решение задач анализа показателей движения. Использование реквизитов

регистра остатков и оборотных регистров

На закладке Объединения/Псевдонимы можем поменять соответствие полей запроса2 именам полей выходной таблицы и добавить следующий запрос, нажав соответствующую кнопку или клавишу Ins.

Формируем третий запрос по таблице остатков регистра ОстаткиНоменклатуры. Указываем в качестве параметра виртуальной таблицы, что остатки надо получать на значение ДатаЮ.

81



Конфигурирование в системе "1С:Предприятие 8.0". Решение оперативных задач

Конфигурирование в системе


Далее на закладке Группировка аналогично предыдущем запросам указываем, что информацию надо группировать по номенклатуре. На закладке Объединения/Псевдонимы указываем окончательный вид выходной таблицы после объединения трех запросов:

Конфигурирование в системе


Итоги сгруппируем по номенклатуре, и, кроме того, поставим галочку Общие итоги.

82



Решение задач анализа показателей движения. Использование реквизитов

регистра остатков и оборотных регистров

Конфигурирование в системе


Зададим данные выходной формы:

Конфигурирование в системе


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

83



Конфигурирование в системе "1С:Предприятие 8.0". Решение оперативных задач

Можно посмотреть текст запроса в сформированной констурктором процедуре. Скорее всего, это будет:

"ВЫБРАТЬ



|ИЗ

ПродажиТек.Номенклатура КАК Номенклатура, ПродажиТек.Номенклатура. Представление, СУММА(ПролажиТек.Количество) КАК КолТек, СУММА(ПродажиТек.Сумма) КАК СумТек, СУММА(О) КАК КолПред, СУММА(О) КАК СумПред, СУММА(О) КАК Ост

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



|ГДЕ

| ПродажиТек.Ссылка.Дата МЕЖДУ ДатаН1 ИДатаК1 И

| ПродажиТек.Ссылка.Проведен = Проведен

[СГРУППИРОВАТЬ ПО

| ПродажиТек. Номенклатура

ОБЪЕДИНИТЬ ВСЕ

|

|ВЫБРАТЬ

| Продажи Пред. Номенклатура,

] ПродажиПред.Номенклатура.Представление,

| СУММА(О),

| СУММА(О),

| СУММА(ПродажиПред.Количество),

| СУММА(ПродажиПред.Сумма),

| СУММА(О)

|ИЗ

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

|ГДЕ

| ПродажиПред.Ссылка.Дата МЕЖДУ ДатаН2 И ДатаК2 И

| ПродажиПред.Ссылка.Проведен = Проведен

|

СГРУППИРОВАТЬ ПО

| ПродажиПред.Номенклатура



Конфигурирование в системе


Решение задач анализа показателей движения. Использование реквизитов

регистра остатков и оборотных регистров

|ОБЪЕДИНИТЬ ВСЕ

|

|ВЫБРАТЬ

| ОстаткиНоменклатурыОстатки. Номенклатура,

| ОстаткиНоменклатурыОстатки.Номенклатура.Представление,

| СУММА(О),

| СУММА(О),

| СУММА(О),

СУММА(О),

СУММА(ОстаткиНоменклатурыОстатки.КоличествоОстаток) |ИЗ

| РегистрНакопления.ОстаткиНоменклатуры.ОстаткиДатаК], ) КАК

ОстаткиНоменклатурыОстатки

|СГРУППИРОВАТЬ ПО

| ОстаткиНоменклатурыОстатки.Номенклатура

(ИТОГИ ПО

| ОБЩИЕ,

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

В режиме 1С предприятие теперь запускаем отчет на формирование:

Чтобы привести отчет к желаемому виду, уберем общий итог по количествам, и в тексте процедуры оставим вывод только верхней группировки (по номенклатуре).

85



Конфигурирование в системе "1С:Предприятие 8.0". Решение оперативных задач

Практикум №12

К данному отчету необходимо добавить колонки с вычислением Прибыли (разница суммы продажи и списанной себестоимости) по каждому периоду. Для этого Вам придется в Запрос1 и Запрос2 получить по имеющимся там товарам еще поля со списанной себестоимостью (расход) из таблицы оборотов по регистру ОстаткиНомеклатуры (или из таблицы ОстатковИОборотов). Подсказка: лучше это делать посредством левого внешнего соединения.

4.2. Отчет Анализ продаж запрос по реквизитам -построение запросом по регистру остатков с использованием реквизитов регистра

Особенно после выполнения последнего практикума виден определенный недостаток предыдущего способа получения отчета -мы объединяли три исходных запроса, да еще и некоторые из них получены посредством соединения нескольких исходных таблиц. В качестве исходных таблиц у нас выступали: Таблица Товары табличной части документа Расходная, таблица остатков и таблица оборотов регистра ОстаткиНоменклатуры. И хотя механизм запросов системы 1С:Предприятие 8.0 позволяет достаточно быстро работать и с большими объемами информации - смущает большое количество исходных таблиц.

Попробуем добиться повышения производительности за счет оптимизации структуры конфигурации.

Что если, все данные выбрать из таблиц регистра ОстаткиНоменклатуры?

Можно получить значение конечного остатка. Можно получить значение количества проданного товара, но вот сумму проданного товара - пока получить не можем. Регистр работает только с себестоимостью.

Что если внести новый ресурс СуммаПродажи?

Если так сделать - получим грубейшую ошибку в работе с регистром остатков.

Напомним, что регистр остатков в качестве ресурсов накапливает данные по показателям остатка. То есть, по таким показателям, по которым принципиально есть положительные и отрицательные движения. Значение каждого ресурса регистра остатков рано или поздно должно иметь возможность выводиться в ноль.

СуммаПродажи - не является показателем остатка. Если расходная накладная будет выполнять по нему движения, как по ресурсу - то

86



Решение задач анализа показателей движения. Использование реквизитов

регистра остатков и оборотных регистров

некому делать движения с обратным знаком, некому принципиально

выводить подобный ресурс в ноль!

В результате при хранении итогов будет неоправданно разбухать физически существующая таблица итогов, опираясь на данные которой 1С:Предприятие 8.0 действительно оперативно выдает остатки по регистру.

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

Отсюда же, кстати, вытекает и второе ограничение:

Нельзя по какому-либо из ресурсов регистра остатков делать рассогласованные по набору измерений движения.

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

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

Для учета характеристик движения на регистрах остатков можно пользоваться Реквизитами регистра.

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

Итак, изменяем структуру регистра накопления

ОстаткиНоменклатуры, вносим в нее реквизит СуммаПродажи. Тип значения - конечно, число. А поскольку учитываем деньги -точность - два знака после запятой.

87





Конфигурирование в системе "1С:Предприятие 8.0". Решение оперативных задач

Конфигурирование в системе


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

//по регистру "ОстаткиНоменклатуры"

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

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

Движение. Регистратор = Ссылка;

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

Движение.Партия = ВыборкаПартий.Партия;

Движение. Количество = КоличествоСп;

Движение.Сумма = СебестоимостьСп;

Если ВыборкаТоваров.КолДок0 Тогда Движение.СуммаПродажи =

КоличествоСп*ВыборкаТоваров.СуммаДок/ВыборкаТоваров.КолДок; Конец Если;

//**



Решение задач анализа показателей движения. Использование реквизитов

регистра остатков и оборотных регистров



Содержание раздела