Описание механизмов партионного учета
Поможем в ✍️ написании учебной работы
Поможем с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой

Содержание статьи.
В данной статье приводится упрощенное описание алгоритма проведения документов по партионному учету (далее ПУ), которое отражает основные особенности данного механизма.
Для упрощения и уменьшения объема данной статьи, в качестве примера использована типовая конфигурация фирмы «1С» «Управление торговлей 10.2». Описание алгоритмов списания партий регламентированного и международного учетов здесь не приводится, поскольку оно практически не отличается от рассматриваемого управленческого учета, за исключением некоторых особенностей, которые будут приведены.

Краткое описание механизма.
Механизмом партионного учета выполняется добавление к существующим движениям документа по регистрам дополнительных движений по регистрам ПУ. Эти движения могут формироваться либо сразу при проведении документа, либо впоследствии, с помощью специальной обработки проведения по партиям. Выбор режима проведения: сразу при проведении документа (далее режим online) или впоследствии обработкой (далее режим offline) выполняется в настройках учетной политики.
Важно отметить, что при использовании offline-режима не выполняется полное перепроведение всего документа – обрабатываются только движения документа, относящиеся к партионному учету, остальные движения при этом не затрагиваются.
Например, документ «Реализация товаров услуг» выполняет движения по регистрам накопления «Товары на складах» и «Партии товаров на складах» (соответственно, последние относятся к ПУ). При использовании обработки проведения документа по партиям движения по регистру «Товары на складах» будут оставаться нетронутыми. Обработкой будут удалены (в случае их наличия) и сформированы заново только движения по «Партии товаров на складах».
Описание принципов действия.
Для «отделения» механизма проведения документа по ПУ от самого документа в конфигурацию был добавлен дополнительный регистр сведений «Списанные товары». В этом регистре документом при проведении сохраняется список товаров с некоторой дополнительной информацией, которые необходимо будет впоследствии списать по партионному учету. Другими словами, можно сказать, что в данный регистр документом помещается «заявка» на проведение по ПУ, в виде информации «что и как» необходимо будет потом списывать. Механизм ПУ эту информацию читает, и выполняет необходимые действия. Механизмы документа, поместившего эти записи, при этом уже не задействуются.
Далее приводится описание основных ресурсов регистра сведений «Списанные товары»:
- Номенклатура – товар, который надо списать по партиям;
- Склад – склад, с которого должна списываться партия (можно не указывать, зависит от параметра учетной политики «Вести партионный учет по складам»);
- ДопустимыйСтатус1…4 – каждая партия товара имеет так называемые статус партии, который ее характеризует, это может быть значение «Купленный», «На комиссию», «По ордеру» и т.д. Соответственно, в данных ресурсах записывается возможные значения статусов, с партий которых данный товар может списаться;
- КодОперацииПартииТоваров – значение перечисления, характеризует выполняемую операцию, например: «Реализация», «Передача на комиссию» и т.д.;
- СчетУчетаБУ (НУ, МУ) – используется при списании партии по регламентированному учету, является аналогом поля ДопустимыйСтатус. То есть, если в управленческом учете партия характеризуется статусом, то в регламентированном учете для этого служит счет учета. Соответственно, в данных ресурсах записываются возможные счета, с партий которых товар должен будет списываться по регламентированному учету.

Запуск механизма проведения документа по ПУ выполняется вызовом процедуры ДвижениеПартийТоваров(). Это может выполняться либо из процедуры ОбработкаПроведения() самого документа (при online-проведении):

ПроводитьПоПартиям = РегистрыСведений.УчетнаяПолитика.ПолучитьПоследнее(Дата).СписыватьПартииПриПроведенииДокументов; Если ПроводитьПоПартиям Тогда ДвижениеПартийТоваров(Ссылка, Движения.СписанныеТовары.Выгрузить()); … КонецЕсли;


Либо из обработки проведения по партиям (offline-режим):

ДвижениеПартийТоваров(Документ, , КоличествоСтрокВДокументе);


Таким образом, входной информацией и единицей обработки для механизма ПУ является ссылка на документ, который необходимо провести.

Процедура ДвижениеПартийТоваров(), а также все остальные процедуры ПУ принадлежат общему модулю УправлениеЗапасамиПартионныйУчет. Для повышения производительности в клиент-серверных версиях, для данного модуля не установлен признак его компиляции на клиенте, зато установлен для сервера. В результате все действия механизма ПУ будут выполняться непосредственно на сервере, а не на более «слабом» клиентском компьютере.

В упрощенном виде алгоритм проведения документа по ПУ можно разбить на несколько логических блоков:
- получение таблицы списания из регистра «Списанные товары»,
- получение остатков по товарам из регистров ПУ,
- подготовка наборов записей регистров обрабатываемого документа,
- выполнение списания партий по таблице списания,
- формирование корреспондирующих движений,
- запись движений документа (наборов записей по регистрам ПУ).

Далее эти блоки будут рассмотрены по отдельности.

Получение таблицы списания из регистра «Списанные товары».
Выполняется в процедуре ДвижениеПартийТоваров().
Как уже было сказано выше, в регистр сведений «Списанные товары» документом помещается информация о том, что именно надо списывать по ПУ. Способ получения этой информации из регистра различается для режимов проведения документа по ПУ. В случае online-проведения вызов указанной процедуры выполняется из модуля документа, поскольку в этом случае существует простая возможность получения этой таблицы из движений документа, данная информация (таблица списания) передается в блок партионного учета из документа параметром процедуры (см. пример выше).
В случае offline-проведения такой возможности нет, поэтому таблица списания получается путем выполнения запроса к регистру «Списанные товары»:

// Если не переданы строки документа, выбираем из базы. Если ТаблицаДокумента = Неопределено Тогда // Таблица строк документов списания ТаблицаДокумента = ПолучитьТаблицуСтрокДокументов(ОбрабатываемыйДокумент); КонецЕсли;


Упрощенно можно сказать, что в процедуре ПолучитьТаблицуСтрокДокументов() выполняется получение записей из регистра сведений «Списанные товары», зарегистрированных обрабатываемым документом. То есть выполняется запрос вида:

ВЫБРАТЬ Регистратор, Период, НомерСтроки, <Перечень все ресурсов регистра> ИЗ РегистрСведений.СписанныеТовары ГДЕ Регистратор = &ОбрабатываемыйДокумент


Результат запроса выгружается в таблицу значений, которая потом передается во все остальные процедуры (далее под ТаблицаСписания будет всегда подразумеваться таблица, полученная в этой функции).

Подготовленная таким образом таблица далее передается в процедуру ВыполнитьСписание().

Получение остатков по товарам из регистров партионного учета.
В данном блоке выполняется запрос к остаткам товаров из таблицы списания в регистрах партионного учета.

Процедура ВыполнитьСписание(ТаблицаСписания, МоментКон, РегламентныйДокумент=Неопределено) // Структура общих параметров, используемых в большинстве процедур СтруктураПараметров = Новый Структура; Если ТаблицаСписания.Количество()>0 Тогда // Выгрузка списка товаров из таблицы списания в массив МассивНоменклатуры = ТаблицаСписания.ВыгрузитьКолонку("Номенклатура"); // из полученного массива с товарами удаляются повторяющиеся позиции, // это делается для уменьшения времени выполнения запросов, где данный // массив используется как параметр УдалитьПовторяющиесяЭлементы(МассивНоменклатуры); СтруктураПараметров.Вставить("УчетнаяПолитика", ПолучитьУчетнуюПолитику(МоментКон)); // Добавление в структуру остатков по партионному учету ПолучитьОстатки(СтруктураПараметров, ТаблицаСписания, МоментКон, МассивНоменклатуры); … КонецЕсли … КонецПроцедуры


Как видно из приведенного кода, в процедуре появляется новый объект СтруктураПараметров. Поскольку данная структура будет использоваться во всех описываемых далее блоках, стоит описать ее чуть подробнее. СтруктураПараметров представляет собой значение типа «Структура», в которую помещаются все необходимые для выполнения в дальнейшем значения. И уже эта структура передается как один параметр во все вызываемые впоследствии процедуры. Из примера приведенного кода видно, что в любом месте, где данная структура доступна, возможно, например, простое обращение к учетной политике через:

СтруктураПараметров.УчетнаяПолитика


Аналогично, результат описываемого здесь получения остатков также сохраняется в этой структуре параметров.
Как можно понять из приведенного кода, получение остатков выполняется в процедуре ПолучитьОстатки().
Остатки партий товаров хранятся в базе данных в регистрах накопления:
- ПартииТоваровНаСкладах – купленные и принятые на комиссию товары,
- ПартииТоваровПереданные – товары переданные на комиссию.
Соответственно, в процедуре ПолучитьОстатки() выполняется запрос к данным регистрам, в зависимости от вида выполняемого списания.

// Процедура ПолучитьОстаткиУпр() вызывается из процедуры ПолучитьОстатки() Процедура ПолучитьОстаткиУпр(СтруктураПараметров, ТаблицаСписания, МоментКон, МассивНоменклатуры) // По партионному учету остатки берутся из двух регистров ЕстьНаСкладах=Ложь; ЕстьПереданные=Ложь; Для Каждого СтрокаСписания Из ТаблицаСписания Цикл // вид выполняемого списания определяется по значению колонки // КодОперацииПартииТоваров строки таблицы списания Источник=ПолучитьИсточникПоКодуОперации(СтрокаСписания.КодОперацииПартииТоваров); Если Источник = "НаСкладах" Тогда // товар будет списываться со склада (с регистра ПартииТовароНаСкладах), // то есть это купленный или принятый на комиссию товар ЕстьНаСкладах=Истина; ИначеЕсли Источник = "Переданные" Тогда // товар списывается с регистра ПартииТоваровПереданные, // то есть товар, переданный на комиссию ЕстьПереданные=Истина; КонецЕсли; КонецЦикла; Если ЕстьНаСкладах Тогда ПолучитьОстаткиПартийНаСкладахУпр(СтруктураПараметров, МоментКон, МассивНоменклатуры); КонецЕсли; Если ЕстьПереданные Тогда ПолучитьОстаткиПартийПереданныхУпр(СтруктураПараметров, МоментКон, МассивНоменклатуры); КонецЕсли; … … КонецПроцедуры // ПолучитьОстаткиУпр()


В процедурах ПолучитьОстаткиПартийНаСкладахУпр() и ПолучитьОстаткиПартийПереданныхУпр() выполняются запросы к соответствующим регистрам накопления, с фильтром по переданному массиву номенклатуры. То есть выполняется запрос вида:

ВЫБРАТЬ ДокументОприходования, // дата документа оприходования партии, необходима для последующей // сортировки в соответствии с выбранной стратегией списания (ФИФО/ЛИФО). ДокументОприходования.Дата, <Перечень всех измерений и ресурсов регистра> ИЗ РегистрНакопления.[ИмяРегистра].Остатки(&МоментКон, Номенклатура В (МассивНоменклатуры))


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

СтруктураПараметров.Вставить("ТаблицаПартииТоваровНаСкладахУпр", Новый ТаблицаЗначений); СтруктураПараметров.Вставить("ТаблицаПартииТоваровНаСкладахУпр", <ПолученнаяТаблицаЗначений>);

 

Подготовка наборов записей регистров обрабатываемого документа
В процессе списания товаров по партиям, механизмом выполняется заполнение соответствующих наборов записей регистров. Первоначальное создание и подготовка этих наборов записей выполняется в данном блоке:

Процедура ВыполнитьСписание(ТаблицаСписания, МоментКон, РегламентныйДокумент=Неопределено) //////////////////////////////////// // получение остатков партий, см. выше //////////////////////////////////// … СоздатьНаборыЗаписей(СтруктураПараметров, ТаблицаСписания); … ПодготовитьНаборыЗаписей(СтруктураПараметров, ТаблицаСписания, СтрокаДокумента.Период, СтрокаДокумента.Регистратор, Истина); … КонецПроцедуры


Коротко описать выполняемые при этом действия можно следующим образом. В процедуре СоздатьНаборыЗаписей() создаются и записываются в структуру параметров наборы записей регистров:

СтруктураПараметров.Вставить("ДвиженияПартииТоваровНаСкладахУпр", РегистрыНакопления.ПартииТоваровНаСкладах.СоздатьНаборЗаписей()); СтруктураПараметров.Вставить("ДвиженияПартииТоваровПереданныеУпр", РегистрыНакопления.ПартииТоваровПереданные.СоздатьНаборЗаписей()); // И т.д.


Которые потом соответствующим образом подготавливаются для записи в процедуре ПодготовитьНаборыЗаписей():

СтруктураПараметров.ДвиженияПартииТоваровНаСкладахУпр.Очистить(); СтруктураПараметров.ДвиженияПартииТоваровНаСкладахУпр.Отбор.Регистратор.Установить(Регистратор);


Кроме того, для некоторых регистров добавляется дополнительный флаг изменения движений по этому регистру:

СтруктураПараметров.Вставить("ИзмененыДвиженияПартииТоваровНаСкладахУпр", Ложь);


и дополнительная таблица движений:

СтруктураПараметров.Вставить("ТаблицаДвиженийПартииТоваровНаСкладахУпр", СтруктураПараметров.ДвиженияПартииТоваровНаСкладахУпр.Выгрузить()); СтруктураПараметров.ТаблицаДвиженийПартииТоваровНаСкладахУпр.Очистить();

 

Выполнение списания партий.
В данном блоке выполняется распределение списываемых товаров по партиям.

Процедура ВыполнитьСписание(ТаблицаСписания, МоментКон, РегламентныйДокумент=Неопределено) //////////////////////////////////// // получение остатков партий, см. выше //////////////////////////////////// // создание наборов записей, см. выше Для Каждого СтрокаДокумента Из ТаблицаСписания Цикл … СписаниеПартий(СтрокаДокумента, СтруктураПараметров, ПолучитьИсточникПоКодуОперации(СтрокаДокумента.КодОперацииПартииТоваров)); … КонецЦикла; КонецПроцедуры


Таким образом, далее единицей обработки алгоритма списания является строка таблицы списания.

Условно действия, выполняемые в процедуре СписаниеПартий() можно разделить на несколько отдельных блоков

Процедура СписаниеПартий(СтрокаДокумента, СтруктураПараметров, РегистрУчета) // 1. Получение таблицы остатков партий из структуры параметров ИмяРегистра = ПолучитьИмяРегистра("ПартииТоваров", РегистрУчета, СтрокаДокумента); // Если нет регистра, по которому списываем, тогда пропускаем Если ИмяРегистра="" Тогда Возврат; КонецЕсли; ТаблицаПартий = СтруктураПараметров["Таблица"+ИмяРегистра] ; // 2. Выборка из полученной таблицы партий строк, соответствующей текущей обрабатываемой // строки таблицы списания НайденныеСтроки = ОтобратьСтрокиПартий(ТаблицаПартий, СтрокаДокумента, РегистрУчета); // 3. Перенос отобранных строк во временную таблицу остатков // Найденные строки перенесем в таблицу значений, которую нужно отсортировать в соответствии со стратегией списания ТаблицаОстатки = Новый ТаблицаЗначений; // Добавим колонку с индексом ТаблицаОстатки.Колонки.Добавить("ИндексНайденнойСтроки", ПолучитьОписаниеТиповЧисла(15, 2)); Для Каждого Кол Из ТаблицаПартий.Колонки Цикл ТаблицаОстатки.Колонки.Добавить(Кол.Имя, Кол.ТипЗначения); КонецЦикла; Сч = 0; Для Каждого Строка Из НайденныеСтроки Цикл НоваяСтрока = ТаблицаОстатки.Добавить(); НоваяСтрока.ИндексНайденнойСтроки = Сч; Для Каждого Кол Из ТаблицаПартий.Колонки Цикл Если ПустаяСтрока(Кол.Имя) ИЛИ Кол.Имя = "QuieryId" Тогда Продолжить; КонецЕсли; НоваяСтрока[Кол.Имя] = Строка[Кол.Имя]; КонецЦикла; Сч = Сч + 1; КонецЦикла; // 4. Сортировка строк таблицы остатков по стратегии списания ОтсортироватьПартииПоСтратегии(ТаблицаОстатки, СтрокаДокумента, СтруктураПараметров); // 5. Распределение списываемого количества по партиям, формирование движений регистров // 6. Перенос изменений во временной таблице остатков в таблицу остатков партий // (уменьшение списанных остатков) КонецПроцедуры


Далее приводится более подробное описание выполняемых действий в перечисленных блоках алгоритма.

1. Из структуры параметров получается таблица остатков партий, заполненная до этого в процедуре ПолучитьОстатки()

2. Выборка из полученной таблицы значений строк, относящиеся к текущей обрабатываемой строке таблицы списания. В упрощенном виде поиск выполняется следующим образом:

СтруктураОтбора = Новый Структура; СтруктураОтбора.Вставить("Номенклатура", СтрокаДокумента.Номенклатура); СтруктураОтбора.Вставить("ХарактеристикаНоменклатуры", СтрокаДокумента.ХарактеристикаНоменклатуры); СтруктураОтбора.Вставить("СерияНоменклатуры", СтрокаДокумента.СерияНоменклатуры); Результат = ТаблицаПартий.НайтиСтроки(СтруктураОтбора);


То есть, отбираются строки по текущему списываемому товару.

3. Общая таблица остатков партий ТаблицаПартий в некоторых случаях может содержать большое количество строк, соответственно сортировка такой таблицы (по стратегии списания в п.4) может занимать значительное количество времени. Поскольку такая сортировка выполняется еще и для каждой строки исходной таблицы списания, это может заметно увеличить время проведения документа по ПУ. Поэтому массив отобранных в п.2 строк переносится в промежуточную таблицу значений ТаблицаОстатки. И далее сортируется уже эта таблица.
Поскольку при списании партий остаток этих партий будет уменьшаться, данные изменения необходимо впоследствии перенести из временной таблицы ТаблицаОстатки обратно в таблицу ТаблицаПартий. Для простого определения соответствия строк этих таблиц в таблицу значений ТаблицаОстатки добавляется дополнительная колонка ИндексНайденнойСтроки, в которой сохраняется индекс соответствующей строки в массиве найденных строк.

4. Сортировка строк таблицы значений ТаблицаОстатки.
Здесь выполняется сортировка строк таблицы значений в соответствии с указанной в учетной политике стратегии списания партий – по хронологии (ФИФО, ЛИФО, по средней) и по статусу (сначала собственные потом принятые или наоборот).
Соответственно при сортировке по хронологии таблица сортируется по колонке с датой документа оприходования партии. Для сортировки по статусу в таблицу добавляется временная колонка ЧислоСтатусПартии, содержащая числовое представление значения статуса партии (0 или 1) - по этой колонке и выполняется сортировка таблицы. После чего колонка удаляется.

5. Распределение списываемого количества по партиям, формирование движений регистров.
Поиск подходящей партии выполняется путем перебор строк таблицы ТаблицаОстатки:

КоличествоОсталосьПогасить = СтрокаДокумента.Количество; Для Каждого СтрокаПартии Из ТаблицаОстатки Цикл Если КоличествоОсталосьПогасить <= 0 Тогда Прервать; КонецЕсли; // Количество по строке больше 0 Если НЕ СтрокаПартии.Количество > 0 Тогда Продолжить; КонецЕсли; // Выполняется проверка соответствия необходимым условиям параметров // партии – склад, на котором хранится партия; ее допустимый статус; // заказ; качество Если НЕ ПроверитьПартию(СтрокаПартии, СтрокаДокумента, СтруктураПараметров, РегистрУчета) Тогда Продолжить КонецЕсли; Если СтрокаПартии.Количество >= КоличествоОсталосьПогасить Тогда КоэффСписания = КоличествоОсталосьПогасить/СтрокаПартии.Количество; Иначе КоэффСписания = 1; КонецЕсли; Движение = ДобавитьДвижение(ПолучитьИмяРегистра("ПартииТоваров", РегистрУчета, СтрокаДокумента), СтруктураПараметров); // Свойства Движение.Период = СтрокаДокумента.Период; Движение.Регистратор = СтрокаДокумента.Регистратор; Движение.Активность = Истина; Движение.ВидДвижения = ВидДвиженияНакопления.Расход; // Измерения Движение.Номенклатура = СтрокаПартии.Номенклатура; // Ресурсы Движение.Количество = Окр(СтрокаПартии.Количество * КоэффСписания,3,1); … … // в таблице значений уменьшается остаток партии СтрокаПартии.Количество = СтрокаПартии.Количество - Движение.Количество; … КонецЦикла;


Отдельно стоит описать примененную здесь функцию ДобавитьДвижение(). Эта функция добавляет новую запись в любой из наборов записей регистров, сохраненных в структуре параметров. Также в ней выполняется установка флага модификации соответствующего регистра, значение данного флага используется впоследствии при записи изменений наборов записей.

Функция ДобавитьДвижение(ИмяРегистра, СтруктураПараметров) Движение = СтруктураПараметров["ТаблицаДвижений" + ИмяРегистра].Добавить(); // параметр ТекНомерСтроки будет описан ниже // в разделе «Формирование корреспондирующих движений». СтруктураПараметров["ТекНомерСтроки"+ИмяРегистра] = СтруктураПараметров["ТекНомерСтроки"+ИмяРегистра]+1; // Устанавливаем флаг модификации СтруктураПараметров["ИзмененыДвижения"+ИмяРегистра] = Истина; Возврат Движение; КонецФункции

 

6. Перенос изменений во временной таблице остатков в таблицу остатков партий.
Все изменения, выполненные во временной таблице ТаблицаОстатки (уменьшение остатка и стоимости партии) необходимо перенести обратно в таблицу остатков партий:

Для Каждого Строка Из ТаблицаОстатки Цикл Для Каждого Кол Из ТаблицаПартий.Колонки Цикл Если ПустаяСтрока(Кол.Имя) ИЛИ Кол.Имя = "QuieryId" Тогда Продолжить; КонецЕсли; // строку в массиве получаем по сохраненному индексу // в колонке ИндексНайденнойСтроки НайденныеСтроки[Строка.ИндексНайденнойСтроки][Кол.Имя] = Строка[Кол.Имя]; КонецЦикла; КонецЦикла;

 

Формирование корреспондирующих движений.
Кроме собственно списания партий при проведении по ПУ может выполняться формирование корреспондирующих движений. Это обусловлено тем, что товар обычно списывается не «насовсем», как правило, он попадает в какой-то другой учет. Хотя система учета основана целиком на отдельных регистрах, каждый из которых отражает отдельные существенные (с точки зрения разработчиков) разделы учета, обычно операции отражаются сразу в нескольких из них, причем связанным образом. В случае с учетом стоимости товаров в большинстве случаев при списании партии выполняются связанные движения в других учетах (если эти учеты предусмотрены в системе), обычно с суммой, равной стоимости товаров (иногда и с количеством).
Например, при проведении по ПУ документа «Реализация товаров и услуг» при реализации по комиссии, кроме собственно списания партии со склада, механизмом выполняется оприходование этой партии в раздел учета переданных на комиссию товаров. Или другими словами, кроме движения списания с регистра «Партии товаров на складах» механизмом выполняется связанное (корреспондирующее) движение в приход по регистру «Партии товаров переданные».

Собственно само формирование этих движений инициируется одновременно со списанием партий в только что рассмотренной процедуре СписаниеПартий() в цикле обхода таблицы остатков партий:

КоличествоОсталосьПогасить = СтрокаДокумента.Количество; Для Каждого СтрокаПартии Из ТаблицаОстатки Цикл Если КоличествоОсталосьПогасить <= 0 Тогда Прервать; КонецЕсли; // Количество по строке больше 0 Если НЕ СтрокаПартии.Количество > 0 Тогда Продолжить; КонецЕсли; … // см. описание действий выше … // в таблице значений уменьшается остаток партии СтрокаПартии.Количество = СтрокаПартии.Количество - Движение.Количество; // Выполнение корреспондирующих движений ВыполнитьКорДвижение(РегистрУчета, СтрокаДокумента, СтруктураПараметров, Движение); ^^^^^^^^^^^^^^^^^^^^ КонецЦикла;


Определение, в каком разделе учета следует выполнить корреспондирующее движение, выполняется функцией ПолучитьНаправлениеСписанияПоКодуОперации()

Процедура ВыполнитьКорДвижение(РегистрУчета, СтрокаДокумента, СтруктураПараметров, Движение) ВыполнитьКорДвижениеУпр(РегистрУчета, ПолучитьНаправлениеСписанияПоКодуОперации(СтрокаДокумента.КодОперацииПартииТоваров, СтрокаДокумента.СтатьяЗатрат), СтрокаДокумента, СтруктураПараметров, Движение); КонецПроцедуры // ВыполнитьКорДвижение() Функция ПолучитьНаправлениеСписанияПоКодуОперации(КодОперации, СтатьяЗатрат = Неопределено) КодыОпераций = Перечисления.КодыОперацийПартииТоваров; НаправлениеСписания = ""; Если КодОперации=КодыОпераций.Реализация ИЛИ КодОперации=КодыОпераций.РеализацияКомиссия ИЛИ КодОперации=КодыОпераций.РеализацияРозница Тогда НаправлениеСписания = "СебестоимостьПродаж"; ИначеЕсли КодОперации=КодыОпераций.ВозвратОтПокупателя Тогда НаправлениеСписания = "СебестоимостьПродаж"; ИначеЕсли КодОперации=КодыОпераций.ПередачаНаКомиссию Тогда НаправлениеСписания = "Переданные"; … … КонецЕсли; Возврат НаправлениеСписания; КонецФункции


Как видно из приведенного кода, определение «направления списания» выполняется путем анализа кода выполняемой операции.
Далее, в соответствие с полученным «направлением» выполняется формирование движений по определенному разделу учета (регистру)

Процедура ВыполнитьКорДвижениеУпр(СписаноИз, ПриходоватьВ, СтрокаДокумента, СтруктураПараметров, Движение) // параметр ПриходоватьВ содержит полученное «направление списания» Если ПриходоватьВ = "НаСкладах" Тогда ПоступлениеНаСкладУпр(СписаноИз, СтрокаДокумента, СтруктураПараметров, Движение); ИначеЕсли ПриходоватьВ = "Переданные" Тогда ПоступлениеПереданныхУпр(СтрокаДокумента, СтруктураПараметров, Движение); ИначеЕсли ПриходоватьВ = "Затраты" Тогда СписаниеНаПостоянныеЗатратыУпр(СтрокаДокумента, СтруктураПараметров, Движение); ИначеЕсли ПриходоватьВ = "СебестоимостьПродаж" Тогда СписаниеНаСебестоимостьПродажУпр(СтрокаДокумента, СтруктураПараметров, Движение); КонецЕсли; КонецПроцедуры


Непосредственно само формирование движений будет рассмотрено на примере процедуры ПоступлениеПереданныхУпр().

Процедура ПоступлениеПереданныхУпр(СтрокаДокумента, СтруктураПараметров, Строка) Учет = "Упр"; // создание новой записи соответствующего набора записей регистра Движение = ДобавитьДвижение("ПартииТоваровПереданные"+Учет, СтруктураПараметров); //////////////////////////////////////////////////// /// заполнение полей записи набора // Свойства Движение.Период = Строка.Период; Движение.Регистратор = Строка.Регистратор; Движение.Активность = Истина; Движение.ВидДвижения = ВидДвиженияНакопления.Приход; Движение.Номенклатура = Строка.Номенклатура; Движение.ХарактеристикаНоменклатуры = Строка.ХарактеристикаНоменклатуры; Движение.ДокументОприходования = Строка.ДокументОприходования; Движение.СтатусПартии = Строка.СтатусПартии; Движение.СтатусПередачи = СтрокаДокумента.СтатусПередачи; Движение.ДоговорКонтрагента = СтрокаДокумента.ДоговорКонтрагента; Движение.ДокументПередачи = СтрокаДокумента.ДокументПередачи; // Вспомогательные поля для списания Движение.ДокументОприходованияДата = Строка.ДокументОприходованияДата; // Ресурсы Движение.Количество = Строка.Количество; Движение.Стоимость = Строка.Стоимость; // Оприходование с новой стоимостью Если Строка.СтоимостьПоступление<>0 Тогда Движение.Стоимость = Строка.СтоимостьПоступление; КонецЕсли; // Реквизиты Движение.КодОперации = СтрокаДокумента.КодОперацииПартииТоваров; // сохранение номера корреспондирующей строки Строка.НомерКорСтроки = СтруктураПараметров["ТекНомерСтрокиПартииТоваровПереданные"+Учет]; КонецПроцедуры


После того, как корреспондирующие движения сформированы, необходимо каким-нибудь способом связать их с «родительскими» движениями списания. Это обусловлено тем, что информация о корреспондирующих движениях может понадобиться в дальнейшем. Например, это может возникнуть, когда стоимость партии выяснилась позже, когда она уже была списана. В результате возникает ситуация, при которой необходимо поправить стоимость выполненного списания партии (например, при дополнительных расходах на приобретение и прочих корректировок стоимости) - естественно при этом нужно поправить стоимость и в корреспондирующем движении.
В конфигурации корреспонденции фиксируются следующим образом: корреспонденция не хранится как отдельная сущность, а может быть получена для определенного движения списания партии. Для того, чтобы знать, какая корреспондирующая запись соответствует данной записи списания по партионному учету, нужно знать:
- куда списана партия (в каком учете (регистре) отражается корреспондирующая запись) (1),
- идентификатор этой записи в данном учете (2).
Для целей (1) используется описанный механизм определения «направления списания» по коду операции - реквизиту регистров партионного учета "КодОперации».
В качестве (2) - документ, которому принадлежат оба движения и номер записи в наборе записей регистра, определяемого кодом операции (1) для этого документа (реквизит "НомерКорСтроки" регистров партий).
В указанном реквизите «НомерКорСтроки» для движения списания партии сохраняется номер соответствующей записи в наборе корреспондирующих движений.

Например, пусть необходимо скорректировать стоимость списанной партии по регистру «Партии товаров на складах». Это влечет за собой коррекцию корреспондирующего движения по регистру «Партии товаров переданные» (предположим, что такая запись есть). Для получения этого движения механизмом ПУ выполняется следующие действия:
- по коду операции списания c помощью функции ПолучитьНаправлениеСписанияПоКодуОперации() определяется регистр, в котором содержится корреспондирующая запись (в данном случае это «Партии товаров переданные»)
- по значению в реквизите «НомерКорСтроки» определяется номер «связанной» записи в наборе записей.

В результате мы имеем набор записей определенного регистра и номер записи в этом наборе. Таким образом, можно однозначно идентифицировать необходимую запись.

Следует понимать, что такой способ накладывает ряд ограничения на правила формирования корреспондирующих движений:
• Для получения набора записей корреспондирующего движения списание партии и корреспондирующая запись должны относиться к одному и тому же документу (регистратору). Здесь нужно отметить, что записи могут быть в наборе записей одного документа, а относиться к другому, в этом случае тот документ, к которому они относятся, записывается в реквизит ДокументДвижения записи списания партий.
• Одной записи списания партии соответствует строго одна корреспондирующая запись (может быть несколько, но с одинаковыми суммами и в разных регистрах).
• Весь набор возможных корреспонденций определен набором кодов операций. Соответствие кодов и корреспонденций определяется в коде рассмотренной функции ПолучитьНаправлениеСписанияПоКодуОперации() и дополнительно нигде не настраивается.
В коде процедуры можно заметить, что номер корреспондирующей записи берется из структуры параметров:

Строка.НомерКорСтроки = СтруктураПараметров["ТекНомерСтрокиПартииТоваровПереданные"+Учет];

Данный параметр создается для регистров в процедуре ПодготовитьНаборыЗаписейУпр() (при этом инициализируется нулевым значением). Впоследствии, при каждом добавлении к набору записей следующей записи, данный параметр увеличивается на единицу (данные действия выполняются в процедуре ДобавитьДвижение(), см. выше). Таким образом в любой момент времени из данного параметра можно получить номер последней добавленной в определенный набор записи.

В регламентированном учете в записи движения списания партий дополнительно заносится информация о счете бухгалтерского учета, на который списан этот товар, и соответствующих субконто (реквизиты регистра "КорСчет", "КорСубконто1...3").

Запись движений документа.
После выполнение всех вышеописанных действий, изменения, внесенные в наборы записей регистров, необходимо записать. Это выполняется в процедуре ЗаписатьДвиженияДокумента().

Процедура ВыполнитьСписание(ТаблицаСписания, МоментКон, РегламентныйДокумент=Неопределено) … … … ЗаписатьДвиженияДокумента(СтруктураПараметров, ТаблицаСписания, Истина); КонецПроцедуры


В данной процедуре анализируется сохраненный в структуре параметров флаг модифицированности регистра, о котором говорилось выше, и в случае если этот флаг установлен, для регистра вызывается процедура переноса сформированных движений в набор:

Если СтруктураПараметров.ИзмененыДвиженияПартииТоваровНаСкладахУпр Тогда ЗаписатьДвижения(СтруктураПараметров.ДвиженияПартииТоваровНаСкладахУпр, СтруктураПараметров.ТаблицаДвиженийПартииТоваровНаСкладахУпр, Замещать); КонецЕсли;


Непосредственно сама запись наборов выполняется в процедуре ЗаписатьДвижения()

Процедура ЗаписатьДвижения(ДвиженияРегистра, ТаблицаДвиженийРегистра, Замещать) // При замещении нужно удалять записи, сформированные прошлым списанием // партий (СписаниеПартий=Истина), // если у регистра есть реквизит СписаниеПартий, то нужно удалить строки с Истина ДМ = ДвиженияРегистра.Метаданные(); ЕстьРеквизитСписаниеПартий = (ДМ.Реквизиты.Найти("СписаниеПартий") <> Неопределено); Если Замещать И ЕстьРеквизитСписаниеПартий Тогда Если ТаблицаДвиженийРегистра=Неопределено Тогда ТаблицаДвиженийРегистра = ДвиженияРегистра.Выгрузить(); КонецЕсли; // чтение сохраненных до этого движений регистра ДвиженияРегистра.Прочитать(); // удаление всех записей, относящихся к механизму // списания партий Инд=0; Пока Инд < ДвиженияРегистра.Количество() Цикл Если ДвиженияРегистра[Инд].СписаниеПартий Тогда ДвиженияРегистра.Удалить(Инд); Иначе Инд=Инд+1; КонецЕсли; КонецЦикла; // Перенос строк из таблицы движений регистра // (заполненной при списании партии) ДобавитьСтрокиВНаборЗаписей(ДвиженияРегистра, ТаблицаДвиженийРегистра); // Заполним параметр "Списание партий" Если ЕстьРеквизитСписаниеПартий Тогда Для Каждого Запись Из ДвиженияРегистра Цикл // установка признака, что данная запись // сформирована механизмом списания партий Запись.СписаниеПартий = Истина; КонецЦикла; КонецЕсли; // запись набора записей ДвиженияРегистра.Записать(Истина); Иначе // В случае, если набор записей записывается в режиме без замещения // существующих записей, или не имеет реквизита СписаниеПартий предварительного // удаления записей не производится. Записи из таблицы движений // добавляются к существующим. Если ТаблицаДвиженийРегистра<>Неопределено Тогда ДобавитьСтрокиВНаборЗаписей(ДвиженияРегистра, ТаблицаДвиженийРегистра); КонецЕсли; // Заполним параметр "Списание партий" Если ЕстьРеквизитСписаниеПартий Тогда Для Каждого Запись Из ДвиженияРегистра Цикл Запись.СписаниеПартий = Истина; КонецЦикла; КонецЕсли; // запись набора записей ДвиженияРегистра.Записать(Замещать); КонецЕсли; КонецПроцедуры

 

Режимы offline- и online-проведения документов по ПУ.
Как уже говорилось выше, документы могут проводиться по партионному учету в двух режимах: когда списание партий выполняется сразу, при проведении документа – режим online; и когда списание партий выполняется позже (например, в конце дня, недели и т.п.) специальной обработкой «Проведение по партиям». С одной стороны метод online кажется более предпочтительным, при его применении после проведения документа сразу появляются все его движения, видно с каких партий списался товар. Но при этом следует учитывать последствия применения этого режима:
- заметно увеличивается время проведения документа
- поскольку механизм партионного учета активно использует объект платформы – последовательность, в online-режиме значительно снижается пропуская способность системы при многопользовательской работе

Поэтому, основным рекомендуемым режимом списания партий является offline-режим.

Особенности реализации обработки «Проведение по партиям».
Данная обработка выполняет «отложенное» проведение документов по партионному учету. В упрощенном виде выполняемые ею действия можно разбить на несколько шагов:
1. Получение списка документов, которые необходимо провести по ПУ.
В список документов попадают документов тех типов, которые могут регистрироваться в последовательности партионного учета за период с границы последовательности по дату, на которую проводятся документы. ВАЖНО учитывать – не все документы, зарегистрированные в последовательности, а все документы из указанного периода, для которых в метаданных конфигурации указан признак их вхождения в эту последовательность.

2. Поочередное проведение документов из списка по ПУ.
Для каждого документы из списка обработкой запускается проведение по партиями, которое было рассмотрено выше. Но здесь есть некоторая особенность – с одной стороны формирование движений по списанию партий должно выполняться в транзакции. С другой стороны попытка провести большое количество документов с большим количеством строк в одной транзакции может не выполниться из-за нехватки ресурсов компьютера. Поэтому здесь применяется промежуточная фиксация транзакции. То есть, обработкой циклически выполняется проводка документов по ПУ, при превышении объемом изменений, вносимых в базу данных, некоторого порога выполняется фиксация открытой транзакции и начало новой. При этом измерением объема изменений является количество строк документов, обработанных в рамках одной транзакции.

3. Установка границы последовательности партионного учета на последний проведенный документ списка.
После выполнения обработки граница последовательности партионного учета устанавливается на последний проведенный документ.

Особенности использования последовательности механизмом партионного учета
Поскольку при списании партий товаров системой используются данные, получаемые из различных регистров на момент документа, в некоторых случаях может возникнуть ситуация (например, при проведении документов задним числом) когда уже проведенные документы некорректно списались по партиям. Поэтому механизмом партионного учета применяется объект платформы – последовательность документов. В типовых конфигурациях такой последовательностью является «ПартионныйУчет».
Как уже было сказано выше, активное применение последовательности заметно сказывается на общей пропускной способности системы. Поэтому в партионном учете она используется с некоторыми особенностями, подробнее см. Правила работы с последовательностями.

 




















































































Дата: 2018-11-18, просмотров: 368.