1C v7.7: Алгоритм механизма детального отслеживания изменения содержимого документов


Денис (DNG) Горбунов, сентябрь-декабрь 2002 года
Резюме: Механизм детального отслеживания изменения реквизитов документов,
интегрируемый небольшими усилиями в любую конфигурацию. Исходные тексты прилагаются.

Оказывается мои алгоритмы способны кому-то навеять вдохновение. Аналог под 1C Предприятие V8: http://infostart.ru/blogs/1062/


Руководители предприятий, борящиеся с неконтролируемыми изменениями
в БД программы 1С: Предприятие, несколько раз обращались ко мне с просьбой добавить
в программу механизм, с помощью которого они могли бы посмотреть что именно
изменилось в данных.
То есть, что было, и что стало (была одна цена такая-то, стала другая такая-то и тому подобное).

Ядро программы 1С: Предприятие 7.7 ведет лог-файл
(в терминах программы - "журнал регистраций"), в который автоматически
заносит много полезной информации.
Однако, при изменении документов фиксируются только
сами факты
изменения, удаления, проведения документов.
О том, что именно и каким образом было изменено в документе
подробных автоматических записей не делается.

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

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

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

Для действия данного механизма требуется инициализация и вызовы его 3-х процедур
из предопределенных процедур формы документа "ПриОткрытии()", "ПриЗакрытии()"
и из предопределенной процедуры модуля документа "ОбработкаПроведения()".

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

Исходный текст и пояснения по интеграции механизма отслеживания изменений документов
в конфигурацию приведены ниже.



// ==========================================================================================
//
// Начало описания процедур механизма отслеживания изменения содержимого документов
//
// ------------------------------------------------------------------------------------------
//
// Механизм отслеживания изменения содержимого документов, версия 1.0
//
// Автор: Денис (DNG) Горбунов, сентябрь-декабрь 2002 года, г.Барнаул
// http://faq1c.gorbunov.ru, http://www.gorbunov.ru
//
// Ядро программы 1С: Предприятие 7.7 (в терминах производителя - "технологическая платформа")
// ведет лог-файл (в терминах программы - "журнал регистраций"), в который автоматически
// заносит много полезной информации. Однако, при изменении документов фиксируются только
// сами факты изменения, удаления, проведения документов. О том, что именно и каким образом было
// изменено в документе подробных автоматических записей не делается.
//
// Данный механизм отслеживания изменения содержимого документов
// встраивается в любую конфигурацию и позволяет записывать
// в стандартный лог-файл программы информацию об старых и новых значениях
// реквизитов при их изменении.
//
// Примечание: изменения фиксируются только при попытках перепроведения
//             ранее проведенных документов (в других случаях, по мнению автора, записи
//			   в лог-файл являются излишними, затрудняющими его просмотр).
//
// Механизм можно небольшими усилиями встроить в любую конфигурацию - 
// это специально учитывалось при разработке.
// Для встраивания данного механизма в конфигурацию тебуется:
//
// 1. Объявить переменные глобального модуля - докЛогОписанияДокументов, 
//					       докЛогВыходБезВопросов,
//					       докЛогСписокДокументов
// 2. Вставить в глобальный модуль процедуры с названием,начинающимся с "докЛог", 
//             которые расположены ниже
// 3. Добавить в тело (то есть после всех функций и процедур, в конец модуля) 
// 			   глобального модуля вызовы докЛогСледитьЗа(...) с указанием
//             вида документа и реквизита, которые подлежат отслеживанию.
//             Если требуется отслеживание изменения нескольких видов реквизитов,
//             то данную процедуру надо вызвать несколько раз, для каждого реквизита
//			   каждого вида документов.
// 4. Добавить в самое начало предопределенной процедуры ПриОткрытии()
//             в модуля формы отслеживаемых документов вызов процедуры
//             докЛогПриОткрытииДокумента(Контекст),
// 5. Добавить в самое начало предопределенной процедуры ПриЗакрытии()
//             в модуля формы отслеживаемых документов вызов процедуры
//             докЛогПриЗакрытииДокумента(Контекст),
// 6. Добавить в самое начало предопределенной процедуры ОбработкаПроведения()
//             в модуля отслеживаемых документов вызов процедуры
//             докЛогПриПроведенииДокумента(Контекст).
//             В ряде конфигураций в глобальном модуле есть
//	       процедура "глПриПроведении(Конт)", которая вызывается при проведении
//	       из всех документов. Можно вставить вызов докЛогПриПроведенииДокумента(Конт)
//             в нее.
//             Обратите внимание, что параметр Контекст используется только, если
//             вызов осуществляется непосредственно из модуля документа. Если же вызов
//	       осуществляется из процедуры глобального модуля глПриПроведении(Конт), 
//	       то в качестве параметра следует использовать то, что получает
//	       в качестве параметра эта процедура, то есть - Конт.
// 7. Если в предопределенной процедуре ПриЗавершенииРаботыСистемы() пользователю
//             задается вопрос о необходимости выхода из системы, то следует
//             добавить условный оператор 
//             "Если докЛогВыходБезВопросов = 0 тогда
//                вопрос о выходе задается
//             КонецЕсли".
//	       Переменная докЛогВыходБезВопросов устанавливается в 1, если
//	       некорректно были заданны параметры при вызовах процедуры докЛогСледитьЗа()
//
// Примечание: Для работы механизма слежения для каждого отслеживаемого вида документов
//             должны быть вызваны процедуры из шагов 2, 4, 5, 6. Если хотя бы один из
//             шагов не выполнен, то никаких сообщений об ошибках выдаваться не будет,
//             но механизм работать не будет.
//             При начальном конфигурировании механизма (вызовами процедуры
//             "докЛогСледитьЗа()"), наоборот, проводится очень тщательная проверка
//             на предмет указания некорректных данных, выводятся сообщения об ошибках
//             и завершается работа программа, ежели были ошибки
//
// ------------------------------------------------------------------------------------------

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

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

	КонецЕсли;
	
	// Таки записи для данного вида документов есть
	// В этом случае добавление имени реквизита документа будет сложнее
	//
	ВремСписокРеквизитовШапки          = Врем.Получить("СписокРеквизитовШапкиИОбщихРеквизитов");
	ВремСписокРеквизитовТабличнойЧасти = Врем.Получить("СписокРеквизитовТабличнойЧасти");
	ВремСтр                            = Врем.Получить("СтрокаВыгрузкиТабличнойЧасти");
	//
	// Сначала ищем, а нет ли уже в списках реквизита с таким именем
	//
	Если (ВремСписокРеквизитовШапки.НайтиЗначение(СокрЛП(ИмяРеквизита))  0) или
	     (ВремСписокРеквизитовТабличнойЧасти.НайтиЗначение(СокрЛП(ИмяРеквизита))  0) тогда
		 Предупреждение("докЛогСледитьЗа(): реквизит """+СокрЛП(ИмяРеквизита)+
		                """ уже внесен в список реквизитов документа """+СокрЛП(ВидДокумента)+""" "+
					    "("""+СокрЛП(СинонимВида)+""").");						
		 докЛогВыходБезВопросов = 1;						
		 ЗавершитьРаботуСистемы(0);
		 Возврат;
    КонецЕсли;

    // Имя реквизита реквизита еще не добавлено в списки
	
	Если ВремГдеРеквизит = 1 тогда // Реквизит находится в шапке
		ВремСписокРеквизитовШапки.ДобавитьЗначение(СокрЛП(ИмяРеквизита), СокрЛП(СинонимРеквизита));
	Иначе // Реквизит находится в табличной части
		ВремСписокРеквизитовТабличнойЧасти.ДобавитьЗначение(СокрЛП(ИмяРеквизита), СокрЛП(СинонимРеквизита));
		ВремПоз = Врем.НайтиЗначение(ВремСтр);
		ВремСтр = ВремСтр + ", " + СокрЛП(ИмяРеквизита);		
		Врем.УстановитьЗначение(ВремПоз, ВремСтр, "СтрокаВыгрузкиТабличнойЧасти");			
	КонецЕсли;
		
КонецПроцедуры

// ------------------------------------------------------------------------------------------
//
// Только для внутреннего использования механизмом слежения за изменением документов
//
Процедура докЛогВыгрузитьРеквизитыДокумента(Конт, ТаблицаВыгрузки, ТаблицаОписания)
	Перем СтрокаВыгрузкиТабличнойЧасти, ТабличнаяЧасть;	
	Перем СписокРеквизитовШапкиИОбщихРеквизитов;
	Перем ИИ, НазваниеРеквизита, ЗначениеРеквизита;
	Перем СписокЗначенийРеквизитовШапки;
	
	// Все проверки на корректность входных данных
	// и все инициализации входных переменных
	//  произведены ранее - можно работать спокойно

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

		СписокЗначенийРеквизитовШапки.ДобавитьЗначение(ЗначениеРеквизита, НазваниеРеквизита);
	КонецЦикла;
	
    Если СписокЗначенийРеквизитовШапки.РазмерСписка() > 0 тогда
		ТаблицаВыгрузки.ДобавитьЗначение(СписокЗначенийРеквизитовШапки, "ЗначенияРеквизитовШапкиИОбщихРеквизитов");
	КонецЕсли;
	
КонецПроцедуры

// ------------------------------------------------------------------------------------------
//
// Начать следить за документом: сохранить старое состояние (значения реквизитов)
// и поместить это состояние в список отслеживаемых
//
// Должна быть вызвана из предопределенной процедуры "ПриОткрытии()" модуля формы
// отслеживаемого документа
//
// Параметр:
// 			Контекст формы документа
//
Процедура докЛогПриОткрытииДокумента(Конт) экспорт
	Перем идДок, ТаблицаСлеженияДокумента, ИИ;	
	Перем ТаблицаОписанияДокумента;
	
	Если (ТипЗначенияСтр(докЛогОписанияДокументов)  "СписокЗначений") или
	     (ТипЗначенияСтр(докЛогСписокДокументов)  "СписокЗначений") тогда
		 // Если механизм слежения не инициализирован,
		 // то ничего делать не следует
		 Возврат;
	КонецЕсли;	
	
	Если Конт.Выбран() = 0 тогда
		// Если документ был только что создан,
		// и не был записан ни разу,
		// то нам здесь делать больше нечего
		Возврат;
	КонецЕсли;
	
	Если Конт.Проведен() = 0 тогда
		// Если документ еще не был проведен,
		// то нам здесь делать больше нечего
		Возврат;
	КонецЕсли;
	
	ТаблицаОписанияДокумента = докЛогОписанияДокументов.Получить(Конт.Вид());
	
	Если ПустоеЗначение(ТаблицаОписанияДокумента) = 1 тогда
		// За документами данного вида слежение не ведется
		Возврат;
	КонецЕсли;
	          
	идДок = ЗначениеВСтрокуВнутр(Конт.ТекущийДокумент());
	
	ТаблицаСлеженияДокумента = докЛогСписокДокументов.Получить(идДок);

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

// ------------------------------------------------------------------------------------------
//
// Закончить следить за документом
//
// Должна быть вызвана из предопределенной процедуры "ПриЗакрытии()" модуля формы
// отслеживаемого документа
//
// Параметр:
//			Контекст формы документа
//
Процедура докЛогПриЗакрытииДокумента(Конт) экспорт
	Перем идДок, ТаблицаСлеженияДокумента, ИИ;	
	Перем ТаблицаОписанияДокумента;
	
	Если (ТипЗначенияСтр(докЛогОписанияДокументов)  "СписокЗначений") или
	     (ТипЗначенияСтр(докЛогСписокДокументов)  "СписокЗначений") тогда
		 // Если механизм слежения не инициализирован,
		 // то ничего делать не следует
		 Возврат;
	КонецЕсли;	
	
	Если Конт.Выбран() = 0 тогда
		// Если документ был только что создан,
		// и не был записан ни разу,
		// то нам здесь делать больше нечего
		Возврат;
	КонецЕсли;
	
	ТаблицаОписанияДокумента = докЛогОписанияДокументов.Получить(Конт.Вид());
	
	Если ПустоеЗначение(ТаблицаОписанияДокумента) = 1 тогда
		// За документами данного вида слежение не ведется
		Возврат;
	КонецЕсли;
	          
	идДок = ЗначениеВСтрокуВнутр(Конт.ТекущийДокумент());
	
	ТаблицаСлеженияДокумента = докЛогСписокДокументов.Получить(идДок);

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

// ------------------------------------------------------------------------------------------
//
// Для внутреннего употребления механизмом слежения за изменением документов
//
// Сравнивает новые и старые значения реквизитов шапки и общих реквизитов документа
//
// Входные параметры:
//		Конт           - контекст документа
//      Описание       - тип "СписокЗначений", список реквизитов шапки и общих реквизитов
//      СтарыеЗначения - тип "СписокЗначений", список старых значений реквизитов
//      НовыеЗначения  - тип "СписокЗначений", список новых значений реквизитов
//
// Выходные параметры:
//      Различия - тип "ТаблицаЗначений", список старых и новых значений реквизитов,
//                 а также их идентификаторы и наименования,
// 				   наименования колонок таблицы: "Идентификатор", "Наименование",
//				   "СтароеЗначение", "НовоеЗначение"
//
Процедура докЛогСравнитьШапку(Конт, Описание, СтарыеЗначения, НовыеЗначения, Различия)
	Перем ИИ, Наименование, Идентификатор;
	Перем СтароеЗначение, ТипСтарогоЗначения;
	Перем НовоеЗначение, ТипНовогоЗначения;
	
	Для ИИ = 1 по Описание.РазмерСписка() цикл
		Идентификатор = Описание.ПолучитьЗначение(ИИ, Наименование);
		
		СтароеЗначение = СтарыеЗначения.Получить(Идентификатор);
		НовоеЗначение = НовыеЗначения.Получить(Идентификатор);
		
		ТипСтарогоЗначения = ТипЗначенияСтр(СтароеЗначение);
		ТипНовогоЗначения = ТипЗначенияСтр(НовоеЗначение);
		
		Если (ТипСтарогоЗначения = ТипНовогоЗначения) тогда			
			Если СтароеЗначение = НовоеЗначение тогда
				Продолжить;
			КонецЕсли;
		КонецЕсли;
		
		// Таки чего-то там не совпадает
		Различия.НоваяСтрока();
		Различия.Идентификатор  = Идентификатор;
		Различия.Наименование   = Наименование;
		Различия.СтароеЗначение = СтароеЗначение;
		Различия.НовоеЗначение  = НовоеЗначение;
	КонецЦикла;
	
КонецПроцедуры

// ------------------------------------------------------------------------------------------
//
// Для внутреннего использования механизмом слежения
//
// Параметры:
//      РазличияШапки          - тип "ТаблицаЗначений", содержит колонки:
//		   				"Идентификатор", "Наименование", "СтароеЗначение", "НовоеЗначение"
//      РазличияТабличнойЧасти - тип "ТаблицаЗначений", содержит колонки:
//						НомерСтрокиСРазличием, 
//						ТипРазличия (1 - изменена строка, 2 - добавлена строка,	3 - удалена строка)
//						ТаблицаРазличий (в свою очередь является структурой типа "ТаблицаЗначений"
//						с колонками "Идентификатор", "Наименование", "СтароеЗначение", "НовоеЗначение")
//
Процедура докЛогЗаписатьРазличияВЛог(Конт, РазличияШапки, РазличияТабличнойЧасти)
	Перем ЕстьРазличияВШапке, ЕстьРазличияВТабличнойЧасти, ОписанияРазличия;

	// А есть ли хоть какие-то различия?
	ЕстьРазличияВШапке = 0;
	ЕстьРазличияВТабличнойЧасти = 0;
	
	Если ПустоеЗначение(РазличияШапки) = 0 тогда
		Если ПустоеЗначение(РазличияШапки.КоличествоСтрок())=0 тогда
			ЕстьРазличияВШапке = 1;
		КонецЕсли;
	КонецЕсли;
	
	Если ПустоеЗначение(РазличияТабличнойЧасти) = 0 тогда
	     Если ПустоеЗначение(РазличияТабличнойЧасти.КоличествоСтрок())=0 тогда
		 	ЕстьРазличияВТабличнойЧасти = 1;
		 КонецЕсли;
	КонецЕсли;

    Если (ЕстьРазличияВШапке = 0) и (ЕстьРазличияВТабличнойЧасти = 0) тогда
		 // Различий нет - писать в лог ничего не надо
		 Возврат;
	КонецЕсли;		

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

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

// ------------------------------------------------------------------------------------------
//
// Для внутреннего употребления механизмом слежения за изменением документов
//
// Сравнивает новые и старые значения реквизитов табличной части документа
//
// Входные параметры:
//		Конт           - контекст документа
//      Описание       - тип "СписокЗначений", список реквизитов табличной части документа
//      СтарыеЗначения - тип "ТаблицаЗначений", таблица старых значений реквизитов табличной части,
//                       получена при помощи вызова метода документа "ВыгрузитьТабличнуюЧасть()"
//      НовыеЗначения  - тип "ТаблицаЗначений", таблица новых значений реквизитов табличной части,
//                       получена при помощи вызова метода документа "ВыгрузитьТабличнуюЧасть()"
//
//
// Выходные параметры:
//      Различия - тип "ТаблицаЗначений", содержит следующие колонки:
//						НомерСтрокиСРазличием, 
//						ТипРазличия (1 - изменена строка, 2 - добавлена строка,	3 - удалена строка)
//						ТаблицаРазличий (в свою очередь является структурой типа "ТаблицаЗначений"
//						с колонками "Идентификатор", "Наименование", "СтароеЗначение", "НовоеЗначение")
//
Процедура докЛогСравнитьТабличнуюЧасть(Конт, Описание, СтарыеЗначения, НовыеЗначения, Различия)
	Перем ДобавленныеСтрокиС, ДобавленныеСтрокиПо;
	Перем УдаленныеСтрокиС, УдаленныеСтрокиПо;
	Перем КоличествоСтарыхСтрок, КоличествоНовыхСтрок;
	Перем ИИ, РазличияВСтроке, РезультатСравнения;
	Перем СодержимоеНовойСтроки, ЖЖ, Стр;
	Перем СодержимоеСтаройСтроки, Идент;

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

		СодержимоеСтаройСтроки = СоздатьОбъект("ТаблицаЗначений");
		
		СодержимоеСтаройСтроки.НоваяКолонка("Идентификатор");
		СодержимоеСтаройСтроки.НоваяКолонка("Наименование");
		СодержимоеСтаройСтроки.НоваяКолонка("СтароеЗначение");
		СодержимоеСтаройСтроки.НоваяКолонка("НовоеЗначение");
		
		Для ЖЖ = 1 по Описание.РазмерСписка() цикл
			Идент = Описание.ПолучитьЗначение(ЖЖ, Стр);
			СодержимоеСтаройСтроки.НоваяСтрока();			
			СодержимоеСтаройСтроки.Идентификатор  = Идент;
			СодержимоеСтаройСтроки.Наименование   = Стр;
			СодержимоеСтаройСтроки.СтароеЗначение = СтарыеЗначения.ПолучитьЗначение(ИИ, Идент);
			СодержимоеСтаройСтроки.НовоеЗначение  = "";
		КонецЦикла;
		
		Различия.НоваяСтрока();
		Различия.НомерСтрокиСРазличием = СтарыеЗначения.ПолучитьЗначение(ИИ, 1); // номер строки всегда в первой колонке
		Различия.ТипРазличия           = 3;
		Различия.ТаблицаРазличий       = СодержимоеСтаройСтроки;

	КонецЦикла;
	
КонецПроцедуры

// ------------------------------------------------------------------------------------------
//
// Сравнить старое и текущее состояние документа и записать разницу в лог
// Делается при проведении документов
//
// Эта процедура должна быть вызвана из предопределенной процедуры
// "ОбработкаПроведения()" модуля документа
//
// Параметр:
//			Контекст модуля документа
//
Процедура докЛогПриПроведенииДокумента(Конт) экспорт
	Перем идДок, ТаблицаСлеженияДокумента;
	Перем ТаблицаОписанияДокумента;
	Перем ТаблицаОписанияШапкиДокумента;
	Перем ТаблицаОписанияТабличнойЧастиДокумента;	
	Перем СтрокаВыгрузкиТабличнойЧасти;
	Перем ТаблицаНовыхРеквизитовДокумента;
	Перем ТаблицаРазличийШапки;
	Перем ТаблицаРазличийТабличнойЧасти;
	Перем СтарыеРеквизитыШапки, НовыеРеквизитыШапки;
	Перем СтарыеРеквизитыТабличнойЧасти, НовыеРеквизитыТабличнойЧасти;	

	Если (ТипЗначенияСтр(докЛогОписанияДокументов)  "СписокЗначений") или
	     (ТипЗначенияСтр(докЛогСписокДокументов)  "СписокЗначений") тогда
		 // Если механизм слежения не инициализирован,
		 // то ничего делать не следует
		 Возврат;
	КонецЕсли;	

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

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

	Если ПустоеЗначение(ТаблицаОписанияШапкиДокумента) = 0 тогда
	
		ТаблицаРазличийШапки = СоздатьОбъект("ТаблицаЗначений");
		ТаблицаРазличийШапки.НоваяКолонка("Идентификатор");
		ТаблицаРазличийШапки.НоваяКолонка("Наименование");
		ТаблицаРазличийШапки.НоваяКолонка("СтароеЗначение");
		ТаблицаРазличийШапки.НоваяКолонка("НовоеЗначение");	
		
		СтарыеРеквизитыШапки = ТаблицаСлеженияДокумента.Получить("ЗначенияРеквизитовШапкиИОбщихРеквизитов");
		НовыеРеквизитыШапки = ТаблицаНовыхРеквизитовДокумента.Получить("ЗначенияРеквизитовШапкиИОбщихРеквизитов");

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

	КонецЕсли; // если ПустоеЗначение(ТаблицаОписанияШапкиДокумента) = 0
	
	// Ищем различия в табличной части
	ТаблицаОписанияТабличнойЧастиДокумента = ТаблицаОписанияДокумента.Получить("СписокРеквизитовТабличнойЧасти");
	СтрокаВыгрузкиТабличнойЧасти = ТаблицаОписанияДокумента.Получить("СтрокаВыгрузкиТабличнойЧасти");
	
	Если ПустоеЗначение(ТаблицаОписанияТабличнойЧастиДокумента) = 0 тогда
		СтарыеРеквизитыТабличнойЧасти = ТаблицаСлеженияДокумента.Получить("ЗначенияРеквизитовТабличнойЧасти");
		НовыеРеквизитыТабличнойЧасти = ТаблицаНовыхРеквизитовДокумента.Получить("ЗначенияРеквизитовТабличнойЧасти");
		
		ТаблицаРазличийТабличнойЧасти = СоздатьОбъект("ТаблицаЗначений");
		ТаблицаРазличийТабличнойЧасти.НоваяКолонка("НомерСтрокиСРазличием"); // номер строки,
																			 // в которой найдены различия
		ТаблицаРазличийТабличнойЧасти.НоваяКолонка("ТипРазличия");      // тип различия: 1 - изменена строка,
																		//               2 - добавлена строка,
																		// 				 3 - удалена строка
		ТаблицаРазличийТабличнойЧасти.НоваяКолонка("ТаблицаРазличий");  // различия в строке, идентична
																		// по структуре как "ТаблицаРазличийШапки"
		
		докЛогСравнитьТабличнуюЧасть(Конт, ТаблицаОписанияТабличнойЧастиДокумента, 
							СтарыеРеквизитыТабличнойЧасти, НовыеРеквизитыТабличнойЧасти, 
							ТаблицаРазличийТабличнойЧасти);
	КонецЕсли;
	
	// Записываем в лог найденные различия	
	докЛогЗаписатьРазличияВЛог(Конт, ТаблицаРазличийШапки, ТаблицаРазличийТабличнойЧасти);
КонецПроцедуры

//
// ------------------------------------------------------------------------------------------
//
// Конец описания процедур механизма отслеживания изменения содержимого документов
//
// ==========================================================================================


Пример инициализации слежения за некоторыми документами
(наименование видов документов и их реквизитов из конфигурации "Комплексная, версия 4.05",
должно также работать и в конфигурации "Торговля 9").
Добавляется в самый конец глобального модуля (в тело модуля - то есть после всех процедур и функций):

Состояние("Инициализация механизма начата...");

докЛогСледитьЗа("ПКО", "Автор");
докЛогСледитьЗа("ПКО", "Фирма");
докЛогСледитьЗа("ПКО", "ЮрЛицо");
докЛогСледитьЗа("ПКО", "ДокОснование");
докЛогСледитьЗа("ПКО", "Касса");
докЛогСледитьЗа("ПКО", "КодОперации");
докЛогСледитьЗа("ПКО", "Контрагент");
докЛогСледитьЗа("ПКО", "Договор");
докЛогСледитьЗа("ПКО", "ФизЛицо");
докЛогСледитьЗа("ПКО", "Счет");
докЛогСледитьЗа("ПКО", "Валюта");
докЛогСледитьЗа("ПКО", "Курс");
докЛогСледитьЗа("ПКО", "Сумма");  
докЛогСледитьЗа("ПКО", "ОблагаетсяНП");

докЛогСледитьЗа("РКО", "Автор");
докЛогСледитьЗа("РКО", "Фирма");
докЛогСледитьЗа("РКО", "ЮрЛицо");
докЛогСледитьЗа("РКО", "ДокОснование");
докЛогСледитьЗа("РКО", "Касса");
докЛогСледитьЗа("РКО", "КодОперации");
докЛогСледитьЗа("РКО", "Контрагент");
докЛогСледитьЗа("РКО", "Договор");
докЛогСледитьЗа("РКО", "ФизЛицо");
докЛогСледитьЗа("РКО", "Счет");
докЛогСледитьЗа("РКО", "Валюта");
докЛогСледитьЗа("РКО", "Курс");
докЛогСледитьЗа("РКО", "Сумма");  
докЛогСледитьЗа("РКО", "ОблагаетсяНП");

докЛогСледитьЗа("Реализация", "Автор");
докЛогСледитьЗа("Реализация", "Фирма");
докЛогСледитьЗа("Реализация", "ЮрЛицо");
докЛогСледитьЗа("Реализация", "КодОперации");
докЛогСледитьЗа("Реализация", "ДокОснование");
докЛогСледитьЗа("Реализация", "Склад");
докЛогСледитьЗа("Реализация", "Контрагент");
докЛогСледитьЗа("Реализация", "Договор");
докЛогСледитьЗа("Реализация", "Валюта");
докЛогСледитьЗа("Реализация", "Курс");
докЛогСледитьЗа("Реализация", "УчитыватьНДС");
докЛогСледитьЗа("Реализация", "СуммаВклНДС");
докЛогСледитьЗа("Реализация", "УчитыватьНП");
докЛогСледитьЗа("Реализация", "СуммаВклНП");
докЛогСледитьЗа("Реализация", "ТипЦен");
докЛогСледитьЗа("Реализация", "Скидка");
докЛогСледитьЗа("Реализация", "ДатаОплаты");
докЛогСледитьЗа("Реализация", "Номенклатура");
докЛогСледитьЗа("Реализация", "Количество");
докЛогСледитьЗа("Реализация", "Единица");
докЛогСледитьЗа("Реализация", "Коэффициент");
докЛогСледитьЗа("Реализация", "Цена");
докЛогСледитьЗа("Реализация", "Сумма");
докЛогСледитьЗа("Реализация", "СуммаНДС");
докЛогСледитьЗа("Реализация", "СуммаНП");
докЛогСледитьЗа("Реализация", "Партия");

докЛогСледитьЗа("РеализацияРозница", "Автор");
докЛогСледитьЗа("РеализацияРозница", "Фирма");
докЛогСледитьЗа("РеализацияРозница", "ЮрЛицо");
докЛогСледитьЗа("РеализацияРозница", "КодОперации");
докЛогСледитьЗа("РеализацияРозница", "ДокОснование");
докЛогСледитьЗа("РеализацияРозница", "Склад");
докЛогСледитьЗа("РеализацияРозница", "Контрагент");
докЛогСледитьЗа("РеализацияРозница", "Договор");
докЛогСледитьЗа("РеализацияРозница", "Валюта");
докЛогСледитьЗа("РеализацияРозница", "Курс");
докЛогСледитьЗа("РеализацияРозница", "УчитыватьНДС");
докЛогСледитьЗа("РеализацияРозница", "СуммаВклНДС");
докЛогСледитьЗа("РеализацияРозница", "УчитыватьНП");
докЛогСледитьЗа("РеализацияРозница", "СуммаВклНП");
докЛогСледитьЗа("РеализацияРозница", "Скидка");
докЛогСледитьЗа("РеализацияРозница", "ДатаОплаты");
докЛогСледитьЗа("РеализацияРозница", "Номенклатура");
докЛогСледитьЗа("РеализацияРозница", "Количество");
докЛогСледитьЗа("РеализацияРозница", "Единица");
докЛогСледитьЗа("РеализацияРозница", "Коэффициент");
докЛогСледитьЗа("РеализацияРозница", "Цена");
докЛогСледитьЗа("РеализацияРозница", "Сумма");
докЛогСледитьЗа("РеализацияРозница", "СуммаНДС");
докЛогСледитьЗа("РеализацияРозница", "СуммаНП");
докЛогСледитьЗа("РеализацияРозница", "Партия");

докЛогСледитьЗа("ПеремещениеТМЦ", "Автор");
докЛогСледитьЗа("ПеремещениеТМЦ", "Фирма");
докЛогСледитьЗа("ПеремещениеТМЦ", "ЮрЛицо");
докЛогСледитьЗа("ПеремещениеТМЦ", "ДокОснование");
докЛогСледитьЗа("ПеремещениеТМЦ", "ФирмаПолучатель");
докЛогСледитьЗа("ПеремещениеТМЦ", "СкладПолучатель");
докЛогСледитьЗа("ПеремещениеТМЦ", "Валюта");
докЛогСледитьЗа("ПеремещениеТМЦ", "Курс");
докЛогСледитьЗа("ПеремещениеТМЦ", "УчитыватьНДС");
докЛогСледитьЗа("ПеремещениеТМЦ", "СуммаВклНДС");
докЛогСледитьЗа("ПеремещениеТМЦ", "УчитыватьНП");
докЛогСледитьЗа("ПеремещениеТМЦ", "СуммаВклНП");
докЛогСледитьЗа("ПеремещениеТМЦ", "ТипЦен");
докЛогСледитьЗа("ПеремещениеТМЦ", "Номенклатура");
докЛогСледитьЗа("ПеремещениеТМЦ", "Количество");
докЛогСледитьЗа("ПеремещениеТМЦ", "Единица");
докЛогСледитьЗа("ПеремещениеТМЦ", "Коэффициент");
докЛогСледитьЗа("ПеремещениеТМЦ", "Цена");
докЛогСледитьЗа("ПеремещениеТМЦ", "Сумма");
докЛогСледитьЗа("ПеремещениеТМЦ", "СуммаНДС");
докЛогСледитьЗа("ПеремещениеТМЦ", "СуммаНП");
докЛогСледитьЗа("ПеремещениеТМЦ", "Партия");

докЛогСледитьЗа("ПоступлениеТМЦ", "Автор");
докЛогСледитьЗа("ПоступлениеТМЦ", "Фирма");
докЛогСледитьЗа("ПоступлениеТМЦ", "ЮрЛицо");
докЛогСледитьЗа("ПоступлениеТМЦ", "КодОперации");
докЛогСледитьЗа("ПоступлениеТМЦ", "ДокОснование");
докЛогСледитьЗа("ПоступлениеТМЦ", "Склад");
докЛогСледитьЗа("ПоступлениеТМЦ", "Контрагент");
докЛогСледитьЗа("ПоступлениеТМЦ", "Договор");
докЛогСледитьЗа("ПоступлениеТМЦ", "Валюта");
докЛогСледитьЗа("ПоступлениеТМЦ", "Курс");
докЛогСледитьЗа("ПоступлениеТМЦ", "УчитыватьНДС");
докЛогСледитьЗа("ПоступлениеТМЦ", "СуммаВклНДС");
докЛогСледитьЗа("ПоступлениеТМЦ", "УчитыватьНП");
докЛогСледитьЗа("ПоступлениеТМЦ", "СуммаВклНП");
докЛогСледитьЗа("ПоступлениеТМЦ", "ТипЦен");
докЛогСледитьЗа("ПоступлениеТМЦ", "НомерДокВходящий");
докЛогСледитьЗа("ПоступлениеТМЦ", "ДатаДокВходящий");
докЛогСледитьЗа("ПоступлениеТМЦ", "ДатаОплаты");
докЛогСледитьЗа("ПоступлениеТМЦ", "Номенклатура");
докЛогСледитьЗа("ПоступлениеТМЦ", "Количество");
докЛогСледитьЗа("ПоступлениеТМЦ", "Единица");
докЛогСледитьЗа("ПоступлениеТМЦ", "Коэффициент");
докЛогСледитьЗа("ПоступлениеТМЦ", "Цена");
докЛогСледитьЗа("ПоступлениеТМЦ", "Сумма");
докЛогСледитьЗа("ПоступлениеТМЦ", "СуммаНДС");
докЛогСледитьЗа("ПоступлениеТМЦ", "СуммаНП");
докЛогСледитьЗа("ПоступлениеТМЦ", "Партия");
докЛогСледитьЗа("ПоступлениеТМЦ", "ВидТМЦ");

докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "Автор");
докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "Фирма");
докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "ЮрЛицо");
докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "ДокОснование");
докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "Склад");
докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "Контрагент");
докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "Договор");
докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "Валюта");
докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "Курс");
докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "ТипЦен");
докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "НомерДокВходящий");
докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "ДатаДокВходящий");
докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "ДатаОплаты");
докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "ГТД");
докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "Таможня");
докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "ТаможенныйСборВал");
докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "ТаможенныйСборВал_Р");
докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "Номенклатура");
докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "Количество");
докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "Единица");
докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "Коэффициент");
докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "Цена");
докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "Сумма");
докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "СуммаНДСРуб");
докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "СуммаПошлиныРуб");
докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "ТаможеннаяСтоимость");
докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "Партия");
докЛогСледитьЗа("ПоступлениеТМЦИмпорт", "ВидТМЦ");

докЛогСледитьЗа("ПоступлениеДопРасходы", "Автор");
докЛогСледитьЗа("ПоступлениеДопРасходы", "Фирма");
докЛогСледитьЗа("ПоступлениеДопРасходы", "ЮрЛицо");
докЛогСледитьЗа("ПоступлениеДопРасходы", "ДокОснование");
докЛогСледитьЗа("ПоступлениеДопРасходы", "Контрагент");
докЛогСледитьЗа("ПоступлениеДопРасходы", "Договор");
докЛогСледитьЗа("ПоступлениеДопРасходы", "Валюта");
докЛогСледитьЗа("ПоступлениеДопРасходы", "Курс");
докЛогСледитьЗа("ПоступлениеДопРасходы", "УчитыватьНДС");
докЛогСледитьЗа("ПоступлениеДопРасходы", "СуммаВклНДС");
докЛогСледитьЗа("ПоступлениеДопРасходы", "УчитыватьНП");
докЛогСледитьЗа("ПоступлениеДопРасходы", "СуммаВклНП");
докЛогСледитьЗа("ПоступлениеДопРасходы", "НомерДокВходящий");
докЛогСледитьЗа("ПоступлениеДопРасходы", "ДатаДокВходящий");
докЛогСледитьЗа("ПоступлениеДопРасходы", "ДатаОплаты");
докЛогСледитьЗа("ПоступлениеДопРасходы", "ДокументПоставки");
докЛогСледитьЗа("ПоступлениеДопРасходы", "Количество");
докЛогСледитьЗа("ПоступлениеДопРасходы", "ОКЕИ");
докЛогСледитьЗа("ПоступлениеДопРасходы", "Цена");
докЛогСледитьЗа("ПоступлениеДопРасходы", "Сумма");
докЛогСледитьЗа("ПоступлениеДопРасходы", "СуммаНДС");
докЛогСледитьЗа("ПоступлениеДопРасходы", "СуммаНП");
докЛогСледитьЗа("ПоступлениеДопРасходы", "Содержание");

Состояние("Инициализация механизма завершена...");


Компьютерные вопросы: 
2002-2012 ©