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