"Партионный учет"

Я работаю в фармацевтической фирме, где при оформлению документов на отгрузку товара требуется указывать цену завода-изготовителя. Если при поступлении новой партии такого товара, предыдущая партия еще не закончилась и цены поступления отличаются, то при учете такого товара возникают некоторые сложности. Ведение нескольких карточек для одного наименования товара часто затруднительно, т.к. , во-первых, при большом ассортименте и движении справочник очень быстро распухает и в нем появляется большое количество дублирующих строк, и, во-вторых, увеличиваются сами базы, что приводит к замедлению работы системы. Аналогичная проблема может возникнуть при создании конфигураций для ИЧП или для решения вопросов сертификации и в других случаях, когда требуется точно знать из какой партии продается товар.

Первая мысль, которая пришла мне в голову - это использование подчиненного справочника. Но когда я рассмотрел конфигурацию для ИЧП Александра Зданевича (размещена на Dev Page), его идея подошла для решения этой проблемы оптимально. Идея заключается в использовании регистра "Товарный запас". Незначительно переработав идею Александра Зданевича и с его согласия я публикую то решение.

Итак регистр "Товарный запас" у нас состоит из следующих компонентов:

В качестве номера серии будет использоваться цена прихода. У Александра Зданевича использовался номер приходной накладной. Можно использовать и номер серии товара, тогда при приходовании товара потребуется каждой серии отводить отдельную строку.

В приходных и расходных документах, в табличной части добавляем значение "Серия". В Модуле приходных документов прописываем движение по регистру "Товарный запас" следующим образом:

Регистр.ТоварныйЗапас.Товар=Товар;
Регистр.ТоварныйЗапас.Количество=Количество;
Регистр.ТоварныйЗапас.Цена=Цена;
Регистр.ТоварныйЗапас.Сумма=Сумма;
Регистр.ТоварныйЗапас.Отгружен=Перечисление.Булево.Да;
Если Товар.Партионный=Да Тогда
....Регистр.ТоварныйЗапас.Серия=Цена;
Иначе
....Регистр.ТоварныйЗапас.Серия=0;
КонецЕсли;
Регистр.ТоварныйЗапас.ДвижениеПриходВыполнить();

В конфигурации предусмотрено, что не для всех товаров ведется партионный учет. Товар имеет свойство "Партионный", имеющее тип "Булево".

При выписывании расходных документов в процедурах "Подбор", "Изменение товара" и пр. вставляет процедуру "Партия(Товар,Склад)" следующего вида

Процедура Партия(Тов,Скл)
Список=СоздатьОбъект("СписокЗначений");
Запрос = СоздатьОбъект("Запрос");
Рег=СоздатьОбъект("Регистр.ТоварныйЗапас");
ТекстЗапроса =
"//{{ЗАПРОС(Отчет)
|Склад = Регистр.ТоварныйЗапас.Склад;
|Товар = Регистр.ТоварныйЗапас.Товар;
|Партия = Регистр.ТоварныйЗапас.Серия;
|КолВо = Регистр.ТоварныйЗапас.Количество;
|Группировка Товар упорядочить по Товар.Наименование без групп;
|Группировка Партия;
|Функция Ост = КонОст(КолВо);
|Условие(Товар=Тов);
|Условие(Склад=Скл);
|"//}}ЗАПРОС
;
// Если ошибка в запросе, то выход из процедуры
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
....Возврат;
КонецЕсли;
Пока Запрос.Группировка("Товар") = 1 Цикл
....Пока Запрос.Группировка("Партия") = 1 Цикл
....Если Запрос.Ост>0 Тогда
........Список.ДобавитьЗначение(Запрос.Партия,"Товар="+Товар+" Серия="+СокрЛП(Запрос.Партия)+" КолВо="+Запрос.Ост);
....КонецЕсли;
....КонецЦикла;
КонецЦикла;
Выб=Список.ВыбратьЗначение(ВыбПар,"Выберите партию",,,0);
Список.ТекущаяСтрока(1);
Если Выб=1 Тогда
....Коли=Рег.СводныйОстаток(Товар,Склад,ВыбПар,,"Количество");
....Серия=ВыбПар;
Иначе
....Если Список.РазмерСписка()=0 Тогда
........Сигнал();
........Предупреждение("Данный товар ни разу не приходывался",0);
....КонецЕсли;
....Предупреждение("Нет данного товара на складе",0);
....Возврат;
КонецЕсли;
КонецПроцедуры

Это позволяет заполнить колонку "Серия" в расходном документе по выбору оператора из любых неизрасходованных партий. Проверка количества списываемого товара прямо в этой процедуре вряд-ли целесообразна, т.к. количество можно изменить и непосредственно в ячейке таблицы документа. Ее наверно удобней разместить в Модуле. Кусок кода модуля документа, отвечающий за проверку доступного количества товара на складе приведен ниже:

ВыбратьСтроки();
Пока( ПолучитьСтроку()>0) Цикл

........ (все необходимые проверки на Товар.Выбран() и пр.)

Ост=Рег.СводныйОстаток(Товар,Склад,Серия,,"Количество");
Если Количество>Ост Тогда
....Предупреждение("На складе нет нужного количества товара "
....+Товар.Наименование + ". На складе осталось "+Ост
....+" "+Товар.ЕдИзм+". Счет ╧ "+НомерДок
....+" от "+ДатаДок+" не проводится!!!");
....НеПроводитьДокумент();
....Возврат;
КонецЕсли;

Регистр.ТоварныйЗапас.Товар=Товар;
Регистр.ТоварныйЗапас.Количество=Количество;
Регистр.ТоварныйЗапас.Цена=Цена;
Регистр.ТоварныйЗапас.Сумма=Сумма;
Регистр.ТоварныйЗапас.Склад=Склад;
Регистр.ТоварныйЗапас.Серия=Серия;
Если Док.Отгружен=Перечисление.Булево.Да Тогда
....Регистр.ТоварныйЗапас.Отгружен=Перечисление.Булево.Да;
Иначе
....Регистр.ТоварныйЗапас.Отгружен=Перечисление.Булево.Нет;
КонецЕсли;
Регистр.ТоварныйЗапас.ДвижениеРасходВыполнить();