Определение закупочной цены на дату каждой продажи

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

В итоге я написал вот такой запрос:

ВЫБРАТЬ
	ТО.Услуга КАК Номенклатура,
	ТО.Ссылка.Дата КАК Дата,
	ТО.Количество КАК Количество,
	ЕСТЬNULL(ТП.Цена, 0) КАК ЦенаЗакупочная
ИЗ
	Документ.Наряд.Услуги КАК ТО
		ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
			ТМ.Номенклатура КАК Номенклатура,
			ТМ.Ссылка.Дата КАК Дата,
			ТМ.Ссылка КАК Ссылка,
			ТМ.Цена КАК Цена
		ИЗ
			Документ.ПоступлениеМатериалов.Материалы КАК ТМ
		ГДЕ
			ТМ.Ссылка.Дата <= &КонецПериода) КАК ТП
		ПО (ТП.Номенклатура = ТО.Услуга)
			И (ТП.Дата <= ТО.Ссылка.Дата)
		ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
			ТМ.Номенклатура КАК Номенклатура,
			ТМ.Ссылка.Дата КАК Дата,
			ТМ.Ссылка КАК Ссылка,
			ТМ.Цена КАК Цена
		ИЗ
			Документ.ПоступлениеМатериалов.Материалы КАК ТМ
		ГДЕ
			ТМ.Ссылка.Дата <= &КонецПериода) КАК ТП2
		ПО (ТП2.Номенклатура = ТО.Услуга)
			И (ТП2.Дата <= ТО.Ссылка.Дата)
			И (ТП2.Дата > ТП.Дата
				ИЛИ ТП2.Дата = ТП.Дата
					И ТП2.Ссылка > ТП.Ссылка)
ГДЕ
	(ТП.Ссылка ЕСТЬ NULL
			ИЛИ ТП2.Ссылка ЕСТЬ NULL)
	И ТО.Ссылка.Дата МЕЖДУ &НачалоПериода И &КонецПериода

Мне понравилась его логика — я соединял две одинаковые таблицы и выдавал только те записи, для которых не было более поздних.

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

И там мне подсказали:

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

Вот честно скажу, сколько не писал такие запросы, никогда не использовал ПЕРВЫЕ 1, а жаль, очень удобный метод, эффективнее и лаконичнее, чем Максимум.

Кстати, анализируя проблему, я понял, почему у меня не получилось решить задачу эффективно. Дело в том, что я писал ТО.Дата, а 1С ругалась, что такого поля нет. Я и подумал, что 1С не увидит в этой области запроса дату из таблицы ТО. А просто нужно было писать ТО.Ссылка.Дата.

У меня получился вот такой довольно простой запрос:

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

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

Поэтому я попробовал сделать гарантированное получение одной записи:

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

Но увы, 1С не допускает подобные конструкции и я получил ошибку:

Поэтому пришлось реализовать это таким образом:

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

Тут важно, что ТМВ сортировать надо не только по дате, но и по ссылке, чтобы в обоих таблицах ТМВ была гарантированно выбрана одна и та же накладная поступления (если их будет две с одинаковой датой).

Может быть у Вас есть вариант попроще? Но в итоге оставил этот, он нормально работал.

Объем: 2 час. Среда: нетленка.

fixin

Программирую на 1С с 1999 года. В 1С просто Гений. В 2020 году ушел из офиса на вольные хлеба фриланса. Принимаю заказы.

Читайте также:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *