На работе столкнулся с такой проблемой как оформление возврата от покупателя. Новый и неопытный продавец на основании Реализации товаров и услуг создала несколько документов Возврат товаров от покупателя. При этом в табличной части Товары в каждом из созданных документов оказалось одинаковое количество товара, которое было продано. Как результат оприходовано больше, чем было продано. Из чего возникла задача доработки процедуры ОбработкаЗаполнения документа ВозвратТоваровОтПокупателя. Возможно решение и не оптимально, но работает. За основу была взята эта публикация. Далее в процедуре ЗаполнитьТоварыПоОснованию(ДокументОснование) модуля документа были внесены следующие изменения:
...
Выборка = РезультатЗапроса.Выбрать();
мСписокПодчиненныхДокументов = ПолучитьПодчиненныеДокументы(ДокументОснование);
Если мСписокПодчиненныхДокументов.Количество() > 0 Тогда
ЗапросВозвращенных = Новый Запрос;
ЗапросВозвращенных.Текст =
"ВЫБРАТЬ
| ВозвратТоваровОтПокупателяТовары.Номенклатура,
| ВозвратТоваровОтПокупателяТовары.ХарактеристикаНоменклатуры,
| СУММА(ВозвратТоваровОтПокупателяТовары.Количество) КАК Количество
|ИЗ
| Документ.ВозвратТоваровОтПокупателя.Товары КАК ВозвратТоваровОтПокупателяТовары
| ЛЕВОЕ СОЕДИНЕНИЕ Документ.ВозвратТоваровОтПокупателя КАК ВозвратТоваровОтПокупателя
| ПО ВозвратТоваровОтПокупателяТовары.Ссылка = ВозвратТоваровОтПокупателя.Ссылка
|ГДЕ
| ВозвратТоваровОтПокупателя.Ссылка В(&СписокВозвратов)
| И ВозвратТоваровОтПокупателя.Проведен = ИСТИНА
|
|СГРУППИРОВАТЬ ПО
| ВозвратТоваровОтПокупателяТовары.Номенклатура,
| ВозвратТоваровОтПокупателяТовары.ХарактеристикаНоменклатуры";
ЗапросВозвращенных.УстановитьПараметр("СписокВозвратов",ПолучитьПодчиненныеДокументы(ДокументОснование));
РезультатЗВ = ЗапросВозвращенных.Выполнить().Выгрузить();
КонецЕсли;
Пока Выборка.Следующий() Цикл
кДобавляемых = Выборка.Количество;
Для Каждого СтрокаРЗВ Из РезультатЗВ Цикл
Если СтрокаРЗВ.Номенклатура = Выборка.Номенклатура И СтрокаРЗВ.ХарактеристикаНоменклатуры = Выборка.ХарактеристикаНоменклатуры Тогда
кДобавляемых = Выборка.Количество - СтрокаРЗВ.Количество;
КонецЕсли;
КонецЦикла;
Если кДобавляемых > 0 Тогда
СтрокаТабличнойЧасти = Товары.Добавить();
СтрокаТабличнойЧасти.Номенклатура = Выборка.Номенклатура;
СтрокаТабличнойЧасти.Количество = кДобавляемых;
СтрокаТабличнойЧасти.ЕдиницаИзмерения = Выборка.ЕдиницаИзмерения;
СтрокаТабличнойЧасти.ЕдиницаИзмеренияМест = Выборка.ЕдиницаИзмеренияМест;
СтрокаТабличнойЧасти.Коэффициент = Выборка.Коэффициент;
СтрокаТабличнойЧасти.СтавкаНДС = Выборка.СтавкаНДС;
СтрокаТабличнойЧасти.ПроцентСкидкиНаценки = Выборка.ПроцентСкидкиНаценки;
СтрокаТабличнойЧасти.ПроцентАвтоматическихСкидок = Выборка.ПроцентАвтоматическихСкидок;
СтрокаТабличнойЧасти.УсловиеАвтоматическойСкидки = Выборка.УсловиеАвтоматическойСкидки;
СтрокаТабличнойЧасти.ЗначениеУсловияАвтоматическойСкидки = Выборка.ЗначениеУсловияАвтоматическойСкидки;
СтрокаТабличнойЧасти.Качество = Выборка.Качество;
СтрокаТабличнойЧасти.Склад = Выборка.Склад;
СтрокаТабличнойЧасти.Цена = Выборка.Цена;
Если ТипДокументаОснования = Тип("ДокументСсылка.ЗаказПокупателя") Тогда
СтрокаТабличнойЧасти.ЗаказПокупателя = ДокументОснование;
Иначе
СтрокаТабличнойЧасти.ЗаказПокупателя = Выборка.ЗаказПокупателя;
КонецЕсли;
Если ОтКомиссионера Тогда
КолвоПереданных = ?(Выборка.КоличествоОстатокПереданных = NULL, 0, Выборка.КоличествоОстатокПереданных);
Если КолвоПереданных>0 Тогда
Сумма = МодульВалютногоУчета.ПересчитатьИзВалютыВВалюту(Выборка.СтоимостьОтданнаяВалОстаток * СтрокаТабличнойЧасти.Количество / КолвоПереданных,
ДоговорКонтрагента.ВалютаВзаиморасчетов, ВалютаДокумента, КурсВзаиморасчетов, мКурсДокумента,
КратностьВзаиморасчетов, мКратностьДокумента);
СтрокаТабличнойЧасти.Сумма = Ценообразование.ПересчитатьЦенуПриИзмененииФлаговНалогов(Сумма,
Перечисления.СпособыЗаполненияЦен.ПоЦенамНоменклатуры,
Истина, УчитыватьНДС, СуммаВключаетНДС,
УчетНДС.ПолучитьСтавкуНДС(СтрокаТабличнойЧасти.СтавкаНДС));
ОбработкаТабличныхЧастей.ПриИзмененииСуммыТабЧасти(СтрокаТабличнойЧасти, ЭтотОбъект, ТекПользователь,,
ЕстьРеквизитПроцентСкидкиНаценки,ПересчитыватьСкидку,
ЕстьАвтоматическиеСкидки,"Товары");
КонецЕсли;
Иначе
СтрокаТабличнойЧасти.Цена = Выборка.Цена;
// Пересчитаем цену в валюту документа (может отличаться от валюты основания).
Цена = МодульВалютногоУчета.ПересчитатьИзВалютыВВалюту(СтрокаТабличнойЧасти.Цена, Выборка.ВалютаДокумента, ВалютаДокумента,
Выборка.КурсДокумента, мКурсДокумента,
Выборка.КратностьДокумента, мКратностьДокумента);
СтрокаТабличнойЧасти.Цена = Ценообразование.ПересчитатьЦенуПриИзмененииФлаговНалогов(Цена,
Перечисления.СпособыЗаполненияЦен.ПоЦенамНоменклатуры,
Выборка.УчитыватьНДС И Выборка.СуммаВключаетНДС,
УчитыватьНДС, СуммаВключаетНДС,
УчетНДС.ПолучитьСтавкуНДС(СтрокаТабличнойЧасти.СтавкаНДС));
ОбработкаТабличныхЧастей.РассчитатьСуммуТабЧасти(СтрокаТабличнойЧасти, ЭтотОбъект);
КонецЕсли;
ОбработкаТабличныхЧастей.РассчитатьКоличествоМестТабЧасти(СтрокаТабличнойЧасти, ЭтотОбъект);
ОбработкаТабличныхЧастей.РассчитатьСуммуНДСТабЧасти(СтрокаТабличнойЧасти, ЭтотОбъект);
СтрокаТабличнойЧасти.ХарактеристикаНоменклатуры = Выборка.ХарактеристикаНоменклатуры;
ОбработкаТабличныхЧастей.ЗаполнитьСкладИОрдерТабЧасти(СтрокаТабличнойЧасти, ЭтотОбъект);
Если ОснованиеРеализацияТоваров Тогда
СтрокаТабличнойЧасти.СерияНоменклатуры = Выборка.СерияНоменклатуры;
СтрокаТабличнойЧасти.ДокументПартии = ДокументОснование;
СтрокаТабличнойЧасти.ЗаказПокупателя = Выборка.ЗаказПокупателя;
КонецЕсли;
Если ЕстьСоставНабора
И Выборка.Комплект Тогда
СтрокаТабличнойЧасти.КлючСтроки = СтрокаТабличнойЧасти.НомерСтроки;
КонецЕсли;
КонецЕсли;
КонецЦикла;
...
После чего логика заполнения документа ВозвратТоваровОтПокупателя изменилась в лучшую сторону. А именно:
На основании реализации может быть введено несколько возвратов. Логика доработки предусматривает этот вариант и добавляет только те позиции, которые не были возвращены ранее.
Далее. После формирования документа возврата продавец может изменить состав документа. Чтобы предотвратить подобные действия в Процедуре ПередЗаписью были внесены следующие изменения:
Перем мСписокПодчиненныхДокументов;
...
//Проверка превышения проданных товаров
Если ЗначениеЗаполнено(Сделка) ТОгда
Если ТипЗнч(Сделка) = Тип("ДокументСсылка.РеализацияТоваровУслуг") Тогда
ЗапросРеализация = Новый Запрос;
ЗапросРеализация.Текст =
"ВЫБРАТЬ
| РеализацияТоваровУслугТовары.Номенклатура,
| РеализацияТоваровУслугТовары.ХарактеристикаНоменклатуры,
| РеализацияТоваровУслугТовары.Количество
|ИЗ
| Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары
| ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
| ПО РеализацияТоваровУслугТовары.Ссылка = РеализацияТоваровУслуг.Ссылка
|ГДЕ
| РеализацияТоваровУслуг.Ссылка = &Реализация";
ЗапросРеализация.УстановитьПараметр("Реализация",Сделка);
РезультатЗапроса = ЗапросРеализация.Выполнить().Выгрузить();
мСписокПодчиненныхДокументов = ПолучитьПодчиненныеДокументы(Сделка);
Если мСписокПодчиненныхДокументов.Количество() > 0 Тогда
ЗапросВозвращенных = Новый Запрос;
ЗапросВозвращенных.Текст =
"ВЫБРАТЬ
| ВозвратТоваровОтПокупателяТовары.Номенклатура,
| ВозвратТоваровОтПокупателяТовары.ХарактеристикаНоменклатуры,
| СУММА(ВозвратТоваровОтПокупателяТовары.Количество) КАК Количество
|ИЗ
| Документ.ВозвратТоваровОтПокупателя.Товары КАК ВозвратТоваровОтПокупателяТовары
| ЛЕВОЕ СОЕДИНЕНИЕ Документ.ВозвратТоваровОтПокупателя КАК ВозвратТоваровОтПокупателя
| ПО ВозвратТоваровОтПокупателяТовары.Ссылка = ВозвратТоваровОтПокупателя.Ссылка
|ГДЕ
| ВозвратТоваровОтПокупателя.Ссылка В(&СписокВозвратов)
| И ВозвратТоваровОтПокупателя.Проведен = ИСТИНА
|
|СГРУППИРОВАТЬ ПО
| ВозвратТоваровОтПокупателяТовары.Номенклатура,
| ВозвратТоваровОтПокупателяТовары.ХарактеристикаНоменклатуры";
Если мСписокПодчиненныхДокументов.Количество() > 1 Тогда
мСписокПодчиненныхДокументов.Удалить(мСписокПодчиненныхДокументов.НайтиПоЗначению(Ссылка));
КонецЕсли;
ЗапросВозвращенных.УстановитьПараметр("СписокВозвратов",мСписокПодчиненныхДокументов);
РезультатЗВ = ЗапросВозвращенных.Выполнить().Выгрузить();
КонецЕсли;
Для Каждого СтрокаТовары Из Товары Цикл
Найден = Ложь;
Для Каждого СтрокаРЗ Из РезультатЗапроса Цикл
Если СтрокаТовары.Номенклатура = СтрокаРЗ.Номенклатура И СтрокаТовары.ХарактеристикаНоменклатуры = СтрокаРЗ.ХарактеристикаНоменклатуры Тогда
Найден = Истина;
кКВозврату = СтрокаРЗ.Количество;
Если мСписокПодчиненныхДокументов.Количество() > 0 Тогда
Для Каждого СтрокаВозвращенных Из РезультатЗВ Цикл
Если СтрокаВозвращенных.Номенклатура = СтрокаТовары.Номенклатура И СтрокаВозвращенных.ХарактеристикаНоменклатуры = СтрокаТовары.ХарактеристикаНоменклатуры Тогда
кКВозврату = кКВозврату - СтрокаВозвращенных.Количество;
КонецЕсли;
КонецЦикла;
КонецЕсли;
Если СтрокаТовары.Количество > кКВозврату Тогда
Сообщить("В документе " + Строка(Сделка) + " указано количество товара " + Строка(СтрокаТовары.Номенклатура)+ " меньше чем в текущем документе, или был оформлен возврат ранее.");
Отказ = Истина;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Если Не Найден Тогда
Отказ = Истина;
Сообщить("Товар " + Строка(СтрокаТовары.Номенклатура) + " не подлежит возврату, так как он отсутствует в документе реализации или был оформлен возврат ранее.");
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЕсли;
...
После отработки этого кода мы гарантированно получаем правильно оформленный документ возврата товаров от покупателя.