Код &НаКлиенте Процедура ОсновноеКонтактноеЛицоПриИзменении(Элемент) Если НЕ ПроверитьЗаполнениеРеквизита() Тогда Сообщить("Выбранное контактное лицо, "+Объект.ОсновноеКонтактноеЛицо+",не работает у контрагента."); КонецЕсли; КонецПроцедуры
&НаСервере Функция ПроверитьЗаполнениеРеквизита() Возврат (Объект.ОсновноеКонтактноеЛицо.ПредставительРаботает); КонецФункции &НаСервере Процедура УстановитьНомерПредставителя()
Объект.ТелефонКонтактногоЛица=Объект.ОсновноеКонтактноеЛицо.КонтактныеСведения; КонецПроцедуры При проверке выдает ошибку: {Справочник.Контрагенты.Форма.ФормаСписка.Форма(12,11)}: Переменная не определена (Объект)
работаю на версии 1С:Предприятие 8.3 (8.3.10.2650) |
Проведение расходного документа, журналы документов, программная работа с документами
Проведение расходного документа
Мы уже настроили проведение документа, который отражает приход материалов. Теперь займемся проведением документа, отвечающего за их списание. Это – документ ОтпускМатериаловМастеру. Для начала сформулируем цели, которых мы хотим достичь при проведении данного документа. Если в случае с документом поступления материалов в нашей конфигурации все довольно просто – нам нужно лишь отразить поступление материалов без каких-либо дополнительных проверок или расчетов, то списание материалов даже в нашем, достаточно простом случае, превращается в непростую задачу.
Во-первых, мы хотим, чтобы система не позволяла списать больше материалов, чем числится за конкретным ответственным лицом. Это означает, что перед формированием движений мы должны сверить данные, введенные в табличную часть документа с данными по остаткам материалов, хранящимися в нашей базе, и, в том случае, если материалов нам не хватит – отказаться проводить документ и сообщить пользователю об ошибке.
Во-вторых, списывая материалы, мы должны придерживаться какой-либо политики оценки. Наиболее простая и широко используемая политика – это списание материалов по средней стоимости.
Предположим, мы приняли две партии одного и того же товара – в первой было 10 единиц по 9 рублей единица (общая стоимость 90 рублей), во второй – 20 единиц по 12 рублей единица (общая стоимость 240 рублей). В регистре мы храним общую стоимость материалов и их общее количество. Поэтому, списывая по методу средней стоимости, например, 15 единиц товара, мы сначала должны найти среднюю стоимость единицы имеющихся товаров, разделив их общую стоимость на общее количество – в нашем случае это (90+240)/(10+20)=11 рублей – и умножить полученную стоимость на количество списываемых товаров – то есть, 11*15=165 рублей. Таким образом, мы сможем оценивать стоимость списанных товаров и оценивать стоимость остатков.
Существуют и другие методы списания материальных ценностей, в частности – это ФИФО, ЛИФО. Вполне можно организовать учет каждой единицы материальных ценностей и списание их по индивидуальной себестоимости. Мы реализуем списание материалов по средней стоимости.
Определившись с нашими двумя основными задачами – реализации списания материалов по средней стоимости и контроля остатков, приступим к работе над процедурой для проведения нашего документа.
Перейдем в модуль объекта документа ОтпускМатериаловМастеру, с помощью панели инструментов Модуль создадим процедуру ОбработкаПроведения. Данные из табличной части мы будем получать с помощью запроса – в дальнейшем мы будем развивать этот запрос для получения необходимых сведений об остатках номенклатуры.
При создании запроса очень удобно пользоваться консолью запросов, которая позволяет в режиме 1С:Предприятие тут же проверять результаты, возвращаемые запросом. Подобные обработки можно найти на дисках ИТС, на различных Интернет-ресурсах, в частности, мы использовали в примерах консоль запросов для управляемого приложения, которую можно найти по адресу: http://nashe1c.ru/materials-view.jsp?id=307.
Итак, обработку консоли запросов следует открыть командой Главное меню > Файл > Открыть. Начнем конструировать запрос, выбрав все поля из таблицы документа ОтпускМатериаловМастеру, рис. 7.1.
ВЫБРАТЬ * ИЗ Документ.ОтпускМатериаловМастеру.Материалы
Мы выбрали все поля из таблицы, не вводя никаких ограничений. Мы собираемся получать данные из таблицы документа, проведением которого мы занимаемся. В запросе же мы получили данные по всем документам. Ограничим наш запрос по документу. Модифицируем запрос в консоли таким образом:
ВЫБРАТЬ * ИЗ Документ.ОтпускМатериаловМастеру.Материалы ГДЕ Ссылка=&Ссылка
Для того, чтобы задать параметр запроса в консоли запросов, перейдем на вкладку Параметры запроса, нажмем на кнопку Заполнить, после чего в поле Значение параметра выберем нужное его значение, в нашем случае – это будет один из документов ОтпускМатериаловМастеру, рис. 7.2.
Выполнив этот запрос, получим таблицу Материалы из указанного документа. Теперь подумаем над тем, какие именно данные нас интересуют. Нам нужны, во-первых, сведения о номенклатуре (поле Номенклатура), во-вторых – о количестве номенклатуры, которую мы хотим списать (поле Количество). Модифицируем запрос следующим образом:
ВЫБРАТЬ ДокМ.Номенклатура, ДокМ.Количество ИЗ Документ.ОтпускМатериаловМастеру.Материалы КАК ДокМ ГДЕ Ссылка=&Ссылка
Этот запрос даст нам такой результат:
В документе мы намеренно смоделировали ситуацию, в которой пользователь, заполняя его, два раза ввел одну и ту же номенклатурную позицию. Сгруппируем теперь результаты запроса по полю Номенклатура – придем к такому тексту запроса:
ВЫБРАТЬ ДокМ.Номенклатура, СУММА (ДокМ.Количество) КАК Количество ИЗ Документ.ОтпускМатериаловМастеру.Материалы КАК ДокМ ГДЕ Ссылка=&Ссылка СГРУППИРОВАТЬ ПО ДокМ.Номенклатура
Здесь мы применили функцию СУММА к количественному показателю и с помощью выражения СГРУППИРОВАТЬ ПО сгруппировали результаты по полю Номенклатура. Это привело к такому результату:
Теперь все данные, которые нужны нам для проведения документа, мы получили. Следующим этапом работы над запросом будет добавление в него команд для выбора нужных данных из регистра накопления ОстаткиМатериалов. Мы приходим к такому запросу:
ВЫБРАТЬ ДокМ.Номенклатура, СУММА (ДокМ.Количество) КАК Количество, МАКСИМУМ (ОстМ.КоличествоОстаток) КАК КоличествоОстатков, МАКСИМУМ (ОстМ.СуммаОстаток) КАК СуммаОстатков ИЗ Документ.ОтпускМатериаловМастеру.Материалы КАК ДокМ ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиМатериалов.Остатки(&МоментВремени) Как ОстМ ПО ДокМ.Номенклатура = ОстМ.Номенклатура ГДЕ Ссылка=&Ссылка СГРУППИРОВАТЬ ПО ДокМ.Номенклатура
Здесь мы соединили таблицу регистра остатков с полученной таблицей документа по полю Номенклатура. К числовым полям, полученным из регистра, мы применили функцию МАКСИМУМ – иначе запрос будет выполняться неверно. В частности, если бы выше мы не выполнили группировку результатов запроса по полю Номенклатура, то в результатах запроса мы получили бы несколько полей с одной и той же номенклатурой, к каждому из которых было бы присоединено одно и то же поле из таблицы регистра.
Поля в таблице документа несут значимую информацию – если даже номенклатура повторяется, это подразумевает то, что пользователь сознательно ввел ее несколько раз (возможно для того, чтобы, выведя печатную форму документа, добавить какие-то дополнительные комментарии). А присоединение к этим данным одних и тех же данных из регистра накопления нас не устраивает. Поэтому мы суммируем данные по количеству материалов из табличной части, а к полям таблицы регистров применяем функцию МАКСИМУМ. Применение функции МАКСИМУМ здесь не принципиально – с тем же успехом можно было бы применить и функцию МИНИМУМ, и другие подходящие – их суть сводится к переходу от нескольких одинаковых значений к одному.
Вышеописанный запрос привел к такому результату:
Номенклатура | Количество | КоличествоОстатков | СуммаОстатков |
---|---|---|---|
Духи | 11 | 36 | 4 899 |
Одеколон | 5 | 18 | 3 510 |
УФ-гель | 7 | 11 | 3 350 |
Лак для волос | 3 | NULL | NULL |
Здесь нас не устраивают два момента. Во-первых, в полях КоличествоОстатков и СуммаОстатков показаны данные по всем ответственным лицам – а нам нужно знать данные лишь по тому ответственному, с которого мы материалы списываем. Во-вторых, по номенклатурной позиции, по которой данных в регистре ОстаткиМатериалов не имеется, в полях находится значение NULL. Для того, чтобы попытка работать с этим значением не привела в будущем к возникновению ошибок, обработаем поля, полученные из регистра, функцией ЕСТЬNULL.
Модифицируем запрос в соответствии с последними соображениями.
ВЫБРАТЬ ДокМ.Номенклатура, СУММА (ДокМ.Количество) КАК Количество, МАКСИМУМ (ЕСТЬNULL(ОстМ.КоличествоОстаток, 0)) КАК КоличествоОстатков, МАКСИМУМ (ЕСТЬNULL(ОстМ.СуммаОстаток, 0)) КАК СуммаОстатков ИЗ Документ.ОтпускМатериаловМастеру.Материалы КАК ДокМ ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиМатериалов.Остатки(&МоментВремени , ОтветственныйСотрудник = &ОтвСотр) Как ОстМ ПО ДокМ.Номенклатура = ОстМ.Номенклатура ГДЕ Ссылка=&Ссылка СГРУППИРОВАТЬ ПО ДокМ.Номенклатура
Здесь мы добавили отбор из регистра только записей, относящихся к заданному ответственному сотруднику (ОтветственныйСотрудник = &ОтвСотр) и применили к показателям количества и суммы, полученным из регистра, функцию ЕСТЬNULL. Если в поле находится NULL, мы заменяем это значение нулем.
Результат запроса теперь выглядит так:
Номенклатура | Количество | КоличествоОстатков | СуммаОстатков |
---|---|---|---|
Духи | 11 | 15 | 1 860 |
Одеколон | 5 | 2 | 400 |
УФ-гель | 7 | 3 | 900 |
Лак для волос | 3 | 0 | 0 |
На данном этапе запрос возвращает нам исключительно те данные, которые нужны для решения задачи. А именно – эти данные позволяют нам понять, хватит ли материалов, числящихся за ответственным лицом, для списания запрошенного в документе количества материалов. Так же, этими данными мы сможем воспользоваться при формировании движений по регистру накопления – эти движения можно будет формировать в цикле обхода результатов запроса.