Восстановление бухгалтерских проводок из резервной базы данных в 1С: 7.7

Обработки - Обработка документов

Пример обработки, позволяющей восстановить (и не только) проводки из резервной базы данных после неосторожного массового изменения и проведения документов за (весьма) длительный период времени. Используется механизм OLE Automation.

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

Именно с такой ситуацией мне и пришлось недавно столкнуться. И речи не было о том, чтобы пытаться пригладить модули проведения документов за 15лет, чтобы они давали ожидаемые проводки (в различных периодах - отличающиеся). Предлагаемая здесь обработка довольно универсальна. Но решает весьма узкую задачу: из резервной базы данных извлекаются проводки документов и записываются в рабочую базу данных. На этом универсальность заканчивается. В процессе, - перед записью, - вы можете внести изменения в сами проводки. Кому-что требуется. Я только обозначил место в обработке, куда нужно втискивать эти дополнительные алгоритмы, удалив оттуда свой конкретный случай в массе не интересный.

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

Глобальный модуль показать/скрыть
Функция ПолучитьРеквизитыПроводок () Экспорт

	Сп = СоздатьОбъект("СписокЗначений")	;
	Для Инд = 1 По Метаданные.РеквизитПроводки() Цикл
		сп.ДобавитьЗначение(Метаданные.РеквизитПроводки(Инд).Идентификатор);
	КонецЦикла;
	Возврат сп;
	
КонецФункции



Функция ПолучитьПроводки (Док, СДополнением=0) Экспорт

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

    Если (Док.Проведен() = 0) И (Док.Вид()<> "Операция")
    Тогда
		Возврат тбПроводки;
    КонецЕсли;

	
	Опер = Док.Операция;
	Опер.ВыбратьПроводки ();
	Пока Опер.ПолучитьПроводку () = 1 Цикл

		тбПроводки.НоваяСтрока();
		тбПроводки.ДтСчет = Опер.Дебет.Счет;
		тбПроводки.ДтСубконто1 = Опер.Дебет.Субконто(1);
		тбПроводки.ДтСубконто2 = Опер.Дебет.Субконто(2);
		тбПроводки.ДтСубконто3 = Опер.Дебет.Субконто(3);
		тбПроводки.КтСчет = Опер.Кредит.Счет;
		тбПроводки.КтСубконто1 = Опер.Кредит.Субконто(1);
		тбПроводки.КтСубконто2 = Опер.Кредит.Субконто(2);
		тбПроводки.КтСубконто3 = Опер.Кредит.Субконто(3);
		тбПроводки.Сумма = Опер.Сумма;
		тбПроводки.Валюта = Опер.Валюта;
		тбПроводки.ВалСумма = Опер.ВалСумма;
		тбПроводки.Количество = Опер.Количество;
		
		Если СДополнением = 1
		Тогда
			Если КвоРеквизитов <> 0
			Тогда
				Для Инд = 1 По КвоРеквизитов Цикл
					ИмяРеквизита = сп.ПолучитьЗначение(Инд);
					тбПроводки.УстановитьЗначение(тбПроводки.КоличествоСтрок(), ИмяРеквизита, Опер.ПолучитьАтрибут(ИмяРеквизита));
				КонецЦикла;
			КонецЕсли;
			тбПроводки.Пометка = 0;
		КонецЕсли;
	КонецЦикла;

	Возврат тбПроводки;

КонецФункции



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



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



Функция  СводныеПроводки (Док) Экспорт
	
	тб = ПолучитьПроводки(Док);
	тб.Свернуть("ДтСчет,КтСчет","Количество,Сумма");
	
	Возврат тб;
	
КонецФункции



//	Возвращает список объектов метаданных указанного типа
Функция глПолучитьСписокОбъектовМетаданных (ТипОбъекта) Экспорт
	сп = СоздатьОбъект("СписокЗначений");

	Если ТипОбъекта = "Константа"
	Тогда
		Для Инд = 1 По Метаданные.Константа() Цикл
			сп.ДобавитьЗначение(Нрег (Метаданные.Константа(Инд).ПолныйИдентификатор()), 
								Метаданные.Константа(Инд).Идентификатор);
		КонецЦикла;

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



Функция ПолучитьЦвет(Красный = 0,Зеленый = 0,Синий = 0) Экспорт
	// функция для формирования значения цвета из составляющих (RGB)
	Возврат Макс(0,Синий)*65536+Макс(0,Зеленый)*256+Макс(0,Красный);
КонецФункции


Функция глНЕ (Оп) Экспорт
	Если Оп = 0
	Тогда
	    Возврат 1;
	Иначе
	    Возврат 0;
	КонецЕсли;
КонецФункции



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

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

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

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

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

Три маленьких кнопки над списками: первая устанавливает все флажки, вторая - сбрасывает, третья - инвертирует. Не думаю, что картинки у вас будут такие же, если вообще будут.

Скачать файлы

Наименование Файл Версия Размер
Восстановление бухгалтерских проводок из резервной базы данных в 1С7.7:
.ert 237,00Kb
29.03.17
2
.ert 237,00Kb 2 Скачать

См. также

Комментарии
1. SQ NT (bullet030) 3 30.03.17 10:37 Сейчас в теме
Бухгалтерский учет, редакция 4.5 (7,70,615)
Секция.Ячейка.ЦветФона (ПолучитьЦвет<<?>>(192, 255, 192));
Функция не обнаружена (ПолучитьЦвет)
Секция.Ячейка.ЦветФона (ПолучитьЦвет(192, 255, 192)<<?>>);
Неопознанный оператор
Секция.Ячейка.ЦветФона (ПолучитьЦвет(192, 255, 192))<<?>>;
Ожидается ключевое слово 'КонецПроцедуры' ('EndProcedure')
Секция<<?>>.Ячейка.Текст = "НомерСтр";
Переменная не определена (Секция)
Секция<<?>>.Ячейка.РамкаОбвести (3, 3, 3, 3);
Переменная не определена (Секция)
Таб<<?>>.ВывестиСекцию (Секция);
Переменная не определена (Таб)
Для НК=1 по тб<<?>>.КоличествоКолонок() Цикл
Переменная не определена (тб)
тб<<?>>.ПолучитьПараметрыКолонки(НК, , Дл, , Назв);
Переменная не определена (тб)
Секция<<?>>.Ячейка.Текст = Назв;
Переменная не определена (Секция)
Секция<<?>>.Ячейка.РамкаОбвести (3, 3, 3, 3);
Переменная не определена (Секция)
Таб<<?>>.ПрисоединитьСекцию (Секция);
Переменная не определена (Таб)
Для НС = 1 По тб<<?>>.КоличествоСтрок() Цикл
Переменная не определена (тб)
Секция = Таб<<?>>.ПолучитьСекцию("Ячейка|Значение");
Переменная не определена (Таб)
Если ИмеетсяПометка <<?>>= 1
Переменная не определена (ИмеетсяПометка)
Пометка = Число (тб<<?>>.ПолучитьЗначение(НС, "Пометка"));
Переменная не определена (тб)
Секция.Ячейка.ЦветФона (ПолучитьЦвет<<?>>(255, 192, 192));
Функция не обнаружена (ПолучитьЦвет)
Секция.Ячейка.ЦветФона (ПолучитьЦвет(255, 192, 192)<<?>>);
Неопознанный оператор
<<?>>КонецЕсли;
Ожидается ключевое слово 'КонецЦикла' ('EndDo')
КонецЕсли<<?>>;
Ожидается ключевое слово 'КонецЦикла' ('EndDo')
При проверке модуля обнаружены синтаксические ошибки!
2. Николай Щербаченко (romasna) 207 30.03.17 10:45 Сейчас в теме
(1)Позволь узнать, ты не забыл добавить процедуры/функции в глобальный модуль? В их перечне есть функция ПолучитьЦвет(...).
3. SQ NT (bullet030) 3 30.03.17 11:05 Сейчас в теме
(2)
ы не забыл добавить процедуры/функции в глобальный модуль
- зачем? где их взять?
Разве нельзя добавить все процедуры/функции в модуль обработки?
4. Николай Щербаченко (romasna) 207 30.03.17 11:13 Сейчас в теме
Нет, все процедуры и функции я не могу включить в состав обработки. Есть жесткие ограничения (OLE). Часть из них все-равно будет в глобальном модуле (должна быть!). А их перечень я указал в статье. Нужно раскрыть ссылку в статье "Глобальный модуль показать/скрыть" и все процедуры/функции из открывшейся области перенести в глобальный модуль твоей конфигурации (рабочей и резервной баз данных). Естественно, если ты сам не программист, рекомендую эксперименты проводить на копиях БД.
5. SQ NT (bullet030) 3 30.03.17 11:25 Сейчас в теме
Хорошо.
- Функция не обнаружена (глНЕ)
6. Николай Щербаченко (romasna) 207 30.03.17 11:29 Сейчас в теме
(5)Спасибо за замечание. Добавил в конец глобального модуля в статье.
7. SQ NT (bullet030) 3 30.03.17 16:17 Сейчас в теме
Ещё
по нажатию кнопки "Сравнить"
тбПроводки.НашаФирма = Опер.НашаФирма;
Поле агрегатного объекта не обнаружено (НашаФирма) Объект (Опер)
8. Николай Щербаченко (romasna) 207 30.03.17 16:33 Сейчас в теме
(7)Моя обработка работает в комплексной конфигурации, в плане счетов есть разделитель учета. Судя по сообщению, у тебя разделителя учета нет. Везде, где найдешь "НашаФирма", - забей строки комментариями //. Например:
//тбПроводки.НашаФирма = Опер.НашаФирма;
Это касается и модуля обработки, и процедур глобального модуля.
9. Николай Щербаченко (romasna) 207 30.03.17 17:17 Сейчас в теме
(7)Строго говоря, стоило бы посмотреть в конфигурации, есть ли разделитель учета. Потому что, если он все-таки имеется, но под другим именем, то "НашаФирма" следовало бы заменить на "ТвойРазделительУчета". Его можно найти в дереве конфигурации. Щелкни дважды мышаком в дереве по "Планы Счетов" и на выпавшей панели справа внизу реквизит "Разделитель учета". Значение его - это и есть ТвойРазделительУчета. Если разделитель не назначен, то достаточно ограничиться комментариями, как я писал в предыдущем сообщении.
10. Николай Щербаченко (romasna) 207 31.03.17 13:53 Сейчас в теме
(7)Я допустил оплошность, не приняв во внимание, что состав доп.реквизитов проводок отличается в различных конфигурациях. Взвалил эту проблему на твою голову. Скачай обновленный файл обработки, замени процедуру глобального модуля ПолучитьПроводки. Не забудь перед ней вставить новую функцию ПолучитьРеквизитыПроводок.
Теперь можно использовать обработку в любой конфигурации без необходимости внесения изменений..
Оставьте свое сообщение