В условии задачи сказано, что могут оказываться как услуги так и товары.
Чтобы отличать какая номенклатура является услугой, а какая товаром создадим у справочника реквизит “ВидНоменклатуры” с типом “ПеречислениеСсылка.ВидыНоменклатуры”. Перечисление “ВидыНоменклатуры” присутствует в каркасной конфигурации изначально.
Если при продаже мы можем оказывать и товары и услуги (доставка, ремонт, установка),то при поступлении услуг быть не должно. Например, нельзя оприходовать услугу “ремонт” в количестве 3 штуки.
Для того чтобы в исключить в приходной накладной добавление услуги у реквизита табличной части “Номенклатура” установим параметр выбора:
Состав этого документа подходит для решения задачи.
Для обоих документов на закладке “Движения” указываем регистры которые будут формировать движения.
Для определения метода списания себестоимости создадим регистр.
Из постановки задачи следует что учетная политика действует год и может быть либо FIFO либо LIFO.
FIFO (First In, First Out – «Первым пришёл — первым ушёл») и LIFO (Last In, First Out – «последним пришёл — первым ушёл») — методы оценки товарно-материальных ценностей. При учёте запасов однородного товара, купленного в разное время по разной цене, приходится определять: что выдавать первым; и физически (на складе),и на бумаге (в бухгалтерских книгах). По методу FIFO первым выдаётся самый старый из пришедших товаров, по методу LIFO — самый новый.
Поскольку учетная политика действует год, периодичность нашего регистра тоже будет “в пределах года”
Описывать разрезы в которых мы будем хранить метод списания себестоимости нам не нужно, а значит измерения в этом регистре нам не нужны. Нам достаточно одного ресурса с типом “ПеречислениеСсылка.УчетнаяПолитика”.
Перечисление “УчетнаяПолитика” изначально присутствует в каркасной конфигурации.
Для того чтобы определить какие создавать регистры (а также их измерения и ресурсы) следует посмотреть на отчеты которые даны в задаче.
Регистр присутствует в каркасной конфигурации изначально.
На закладке “Прочее” включим у регистра свойство “Разрешить разделение итогов” оно влияет на параллельность работы системы и в каркасной конфигурации по умолчанию выключено.
При создании нового регистра, данное свойство по умолчанию включено.
Посмотрев на отчет, становится понятно, что остатки должны быть в разрезе номенклатуры и партии, а значит измерения будет два:
Прибыль - будет вычисляться при выводе отчета, поэтому в регистр не добавляем.
Данный регистр отсутствует в каркасной конфигурации, его создаем сами. Необходимость этого регистра определяется с помощью отчета который требуется для решения задачи. Поскольку в заголовке отчета написано “Продажи с 01.01.2010 по 31.03.2010” мы с вами выбираем вид регистра “Обороты”.
Для того чтобы определить вид регистра, нужно выбрать один из подходящих ответов:
Наличие ресурсов и измерений мы с вами уже научились определять (подсказкой является отчет).
Перечисления УчетнаяПолитика и ВидыНоменклатуры в каркасной конфигурации присутствуют изначально и для решения задачи нет никакой необходимости их редактировать.
По умолчанию отчетов в каркасной конфигурации нет, они создаются вручную. Создадим два отчета ПродажаТоваров и ОстаткиНоменклатуры Для каждого отчета создадим схему компоновки данных и пока на этом закончим.
Для проведения этого документа в рамках поставленной задачи достаточно конструктора движений, но в нашем решении будет использоваться запрос чтобы можно было избавиться от дублей строк в случае если пользователь в табличной части документа указал два раза одну и ту же номенклатуру.
Процедура ОбработкаПроведения(Отказ, Режим) //Запись текущего набора записей //Будут очищены предыдущие записи Движения.ОстаткиНоменклатуры.Записывать = Истина; //В запросе выбираем из табличной части документа номенклатуру, количество и сумму(себестоимость) //В поле "Период" указываем дату документа с помощью параметра //Партией является сам документ //Группируем номенклатуру чтобы избежать дубли строк(одинаковую номенклатуру) //Суммируем поля "Количество" и "Себестоимость" чтобы при дублях номенклатуры отобразилась их сумма Запрос = Новый Запрос; Запрос.Текст = "ВЫБРАТЬ | ПриходнаяНакладнаяСписокНоменклатуры.Номенклатура КАК Номенклатура, | СУММА(ПриходнаяНакладнаяСписокНоменклатуры.Количество) КАК Количество, | СУММА(ПриходнаяНакладнаяСписокНоменклатуры.Сумма) КАК Себестоимость, | &Период КАК Период, | ПриходнаяНакладнаяСписокНоменклатуры.Ссылка КАК Партия |ИЗ | Документ.ПриходнаяНакладная.СписокНоменклатуры КАК ПриходнаяНакладнаяСписокНоменклатуры |ГДЕ | ПриходнаяНакладнаяСписокНоменклатуры.Ссылка = &Ссылка | |СГРУППИРОВАТЬ ПО | ПриходнаяНакладнаяСписокНоменклатуры.Номенклатура, | ПриходнаяНакладнаяСписокНоменклатуры.Ссылка"; //Параметр "Ссылка" для выбора конкретного документа //Параметр "Период" для того, чтобы использовать ЗаполнитьЗначенияСвойств() Запрос.УстановитьПараметр("Ссылка", Ссылка); Запрос.УстановитьПараметр("Период", Дата); РезультатЗапроса = Запрос.Выполнить(); Выборка = РезультатЗапроса.Выбрать(); Пока Выборка.Следующий() Цикл //Делаем движения с видом "приход" Движение = Движения.ОстаткиНоменклатуры.ДобавитьПриход(); //Заполняем свойства переменной "Движение" ЗаполнитьЗначенияСвойств(Движение, Выборка); КонецЦикла; КонецПроцедуры Для проведения этого документа, необходимо сначала определиться с выбором методики проведения. В этом нам поможет блок-схема представленная ниже.
Данных в самом документе нам недостаточно, поэтому использовать будем традиционную методику проведения.
Процедура ОбработкаПроведения(Отказ, Режим) //Проверяем указан ли метод списания себестоимости МетодСписанияСебестоимости = РегистрыСведений.УчетнаяПолитика.ПолучитьПоследнее(Дата).МетодСписания; //Если метод списания не указан, отказываемся проводить документ Если Не ЗначениеЗаполнено(МетодСписанияСебестоимости) Тогда Отказ = Истина; Сообщение = Новый СообщениеПользователю; Сообщение.Текст = "Не указана учетная политика"; Сообщение.Сообщить(); Возврат; КонецЕсли; Движения.ОстаткиНоменклатуры.Записать(); Движения.ОстаткиНоменклатуры.Записывать = Истина; Движения.Продажи.Записывать = Истина; //Блокировка в старой методике проведения Блокировка = Новый БлокировкаДанных; ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.ОстаткиНоменклатуры"); //Блокируемый регистр ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный; //Блокируем чтение и запись данных ЭлементБлокировки.ИсточникДанных = СписокНоменклатуры; //Данные для блокировки будем брать из табличной части документа ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Номенклатура", "Номенклатура"); //Блокировать в регистре будем номенклатуру (Параметр1) которая находится в документе (Параметр2) Блокировка.Заблокировать(); //Регистр ОстаткиНоменклатуры Запрос = Новый Запрос; Запрос.Текст = //Берем данные из табличной части документа //Группируем по номенклатуре и виду номенклатуры для исключения дублей строк //Суммируем количество, цену и сумму чтобы избавиться от дублей //Индексируем по номенклатуре т.к. будем использовать ее для связей (+ускорение) "ВЫБРАТЬ | РасходнаяНакладнаяСписокНоменклатуры.Номенклатура КАК Номенклатура, | РасходнаяНакладнаяСписокНоменклатуры.Номенклатура.ВидНоменклатуры КАК НоменклатураВидНоменклатуры, | СУММА(РасходнаяНакладнаяСписокНоменклатуры.Количество) КАК Количество, | СУММА(РасходнаяНакладнаяСписокНоменклатуры.Цена) КАК Цена, | СУММА(РасходнаяНакладнаяСписокНоменклатуры.Сумма) КАК Сумма |ПОМЕСТИТЬ ВТ_ТЧ_Товары |ИЗ | Документ.РасходнаяНакладная.СписокНоменклатуры КАК РасходнаяНакладнаяСписокНоменклатуры |ГДЕ | РасходнаяНакладнаяСписокНоменклатуры.Ссылка = &Ссылка | |СГРУППИРОВАТЬ ПО | РасходнаяНакладнаяСписокНоменклатуры.Номенклатура, | РасходнаяНакладнаяСписокНоменклатуры.Номенклатура.ВидНоменклатуры | |ИНДЕКСИРОВАТЬ ПО | Номенклатура |; | //Из регистра берем партию (для порядка используем момент времени, от этого зависит ФИФО или ЛИФО //КоличествоОстаток(сколько осталось товара) и СебестоимостьОстаток(себестоимость товара из прихода = сумма) проверяем на null т.к. левое соединение и может быть ситуация когда номенклатуры на остатках нет //Сумма (из документа) //Параметр &МоментВремени для того чтобы учесть движения текущего документа //В условии ВТ регистра накопления отбираем только ту номенклатуру которая у нас в ТЧ документа (которая помещена в ВТ) //Выбираем номенклатуру только с видом "Товар", т.к. услуг не должно быть на остатках |//////////////////////////////////////////////////////////////////////////////// |ВЫБРАТЬ | ОстаткиНоменклатурыОстатки.Партия КАК Партия, | ОстаткиНоменклатурыОстатки.Партия.Представление КАК ПартияПредставление, | ВТ_ТЧ_Товары.Номенклатура КАК Номенклатура, | ВТ_ТЧ_Товары.Номенклатура.Представление КАК НоменклатураПредставление, | ВТ_ТЧ_Товары.НоменклатураВидНоменклатуры КАК НоменклатураВидНоменклатуры, | ВТ_ТЧ_Товары.Количество КАК Количество, | ЕСТЬNULL(ОстаткиНоменклатурыОстатки.КоличествоОстаток, 0) КАК КоличествоОстаток, | ЕСТЬNULL(ОстаткиНоменклатурыОстатки.СебестоимостьОстаток, 0) КАК СебестоимостьОстаток, | ВТ_ТЧ_Товары.Сумма КАК Сумма |ИЗ | ВТ_ТЧ_Товары КАК ВТ_ТЧ_Товары | ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиНоменклатуры.Остатки( | &МоментВремени, | Номенклатура В | (ВЫБРАТЬ | ВТ_ТЧ_Товары.Номенклатура КАК Номенклатура | ИЗ | ВТ_ТЧ_Товары КАК ВТ_ТЧ_Товары | ГДЕ | ВТ_ТЧ_Товары.НоменклатураВидНоменклатуры = ЗНАЧЕНИЕ(Перечисление.ВидыНоменклатуры.Товар))) КАК ОстаткиНоменклатурыОстатки | ПО ВТ_ТЧ_Товары.Номенклатура = ОстаткиНоменклатурыОстатки.Номенклатура | |УПОРЯДОЧИТЬ ПО | ОстаткиНоменклатурыОстатки.Партия.МоментВремени |ИТОГИ | МАКСИМУМ(НоменклатураВидНоменклатуры),| МАКСИМУМ(Количество),| СУММА(КоличествоОстаток),| СУММА(СебестоимостьОстаток),| МАКСИМУМ(Сумма) |ПО | Номенклатура"; //Если ЛИФО тогда порядок партий по убыванию //Если ФИФО то ничего не меняем, т.к. порядок в запросе и так подразумевает ФИФО Если МетодСписанияСебестоимости = Перечисления.УчетнаяПолитика.ЛИФО Тогда Запрос.Текст = СтрЗаменить(Запрос.Текст, "ОстаткиНоменклатурыОстатки.Партия.МоментВремени", "ОстаткиНоменклатурыОстатки.Партия.МоментВремени УБЫВ"); КонецЕсли; Запрос.УстановитьПараметр("Ссылка", Ссылка); Запрос.УстановитьПараметр("МоментВремени", МоментВремени()); РезультатЗапроса = Запрос.Выполнить(); ВыборкаНоменклатура = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам); Пока ВыборкаНоменклатура.Следующий() Цикл //Для накопления себестоимостей разных партий Стоимость = 0; //Если товар, тогда выполняем контроль остатков Если ВыборкаНоменклатура.НоменклатураВидНоменклатуры = Перечисления.ВидыНоменклатуры.Товар Тогда //Если пытаемся списать больше чем есть тогда отказываемся проводить Если ВыборкаНоменклатура.Количество > ВыборкаНоменклатура.КоличествоОстаток Тогда Отказ = Истина; Сообщение = Новый СообщениеПользователю; Сообщение.Текст = СтрШаблон("Недостаточно товара %1 в количестве %2", ВыборкаНоменклатура.НоменклатураПредставление, //Выводим пользователю сообщение о том, сколько товара не хватает ВыборкаНоменклатура.Количество - ВыборкаНоменклатура.КоличествоОстаток); Сообщение.Сообщить(); //Чтобы вывести сообщения для всей номенклатуры которой может не хватить Продолжить; КонецЕсли; //Если хватает номенклатуры то по партиям обходим ее ВыборкаДетальныеЗаписи = ВыборкаНоменклатура.Выбрать(); //Сколько нужно списать номенклатуры ОсталосьСписать = ВыборкаНоменклатура.Количество; //Пока не будет списано все количество номенклатуры которое нам нужно Пока ВыборкаДетальныеЗаписи.Следующий() И ОсталосьСписать > 0 Цикл //Выбираем сколько списать из партии выбрав минимальное значение из того сколько нам осталось списать и сколько номенклатуры в текущей партии СписатьИзПартии = Мин(ОсталосьСписать, ВыборкаДетальныеЗаписи.КоличествоОстаток); //Если нам нужно списать количество равное тому сколько сейчас номенклатуры в партии //то себестоимость будет равна себестоимости самой партии, т.к. она берется целиком Если СписатьИзПартии = ВыборкаДетальныеЗаписи.КоличествоОстаток Тогда Себестоимость = ВыборкаДетальныеЗаписи.СебестоимостьОстаток; Иначе //Чтобы не получилось деления на ноль Если ВыборкаДетальныеЗаписи.КоличествоОстаток = 0 Тогда Отказ = Истина; Сообщение = Новый СообщениеПользователю; Сообщение.Текст = СтрШаблон("По партии %1 нулевой остаток", ВыборкаДетальныеЗаписи.ПартияПредставление); Сообщение.Сообщить(); Прервать; КонецЕсли; //Проблема копеек //В обычном случае было бы: ВыборкаДетальныеЗаписи.СебестоимостьОстаток / ВыборкаДетальныеЗаписи.КоличествоОстаток * СписатьИзПартии Себестоимость = ВыборкаДетальныеЗаписи.СебестоимостьОстаток * СписатьИзПартии / ВыборкаДетальныеЗаписи.КоличествоОстаток; КонецЕсли; Движение = Движения.ОстаткиНоменклатуры.ДобавитьРасход(); Движение.Период = Дата; Движение.Номенклатура = ВыборкаДетальныеЗаписи.Номенклатура; Движение.Партия = ВыборкаДетальныеЗаписи.Партия; Движение.Количество = СписатьИзПартии; Движение.Себестоимость = Себестоимость; //Вычитаем списанное количество для следующей итерации ОсталосьСписать = ОсталосьСписать - СписатьИзПартии; //Накапливаем общую сумму которую списываем с партий Стоимость = Стоимость + Себестоимость; КонецЦикла; КонецЕсли; Движение = Движения.Продажи.Добавить(); Движение.Номенклатура = ВыборкаНоменклатура.Номенклатура; Движение.Период = Дата; Движение.Количество = ВыборкаНоменклатура.Количество; Движение.Сумма = ВыборкаНоменклатура.Сумма; Движение.Себестоимость = Стоимость; КонецЦикла; КонецПроцедуры Формы отчетов должны выглядеть так, как это указано в задании. Ниже будут представлены основные настройки схемы компоновки данных по каждому отчету.
Чтобы воспроизвести отчет из задачи необходимо партию привести к определенному формату. Если вывести номер партии через “Партия.Номер” то будут отображаться лидирующие нули, но в отчете из задачи лидирующих нулей нет. Для этого создаем общий модуль “НумерацияОбъектов” который будем использовать в выражении представления.
Функция НомерНаПечать(Стр) Экспорт Пока Лев(Стр, 1) = "0" Цикл Стр = Сред(Стр, 2); КонецЦикла; Возврат Стр; КонецФункцииСсылка на скачивание dt
Будьте в курсе всех изменений в сфере ИТ с Тарифами 1С:ИТС.