Учет и сверка Z-Отчетов ККМ в 1С

03.06.18

Учетные задачи - Кассовые операции

Думаю, все крупные компании при внедрении/эксплуатации 1С делают значительные изменения в ее конфигурации. Как бы вы ни пытались все бизнес процессы решить типовыми решениями от 1С, все равно наступает момент, когда приходится заняться конфигурированием. Я решил написать серию статей, где постараюсь описать решения, которые мне пришлось реализовывать в разных компаниях. Если разработчики 1С посчитают что-то интересным для внедрения в типовые решения, мы будем только рады. В текущей статье речь пойдет о кассовых z-отчетах в 1С.

ПРЕДПОСЫЛКИ:

Если вы используете ККМ, у вас возникает необходимость сверять отраженную выручку в 1С с предоставленными z-отчетами.

Сразу развею миф: «Если все чеки печатаются из 1С, то и сумма выручки всегда будет совпадать с z-отчетом». В жизни все не так.

Если у вас всего 1-5 контрольно кассовых машин (ККМ), можно ежедневно вручную бухгалтеру сверять выручку по бумажному z-отчету. Но если у вас более 100 ККМ, вопрос автоматизации по проверке достоверности отражения выручки, соблюдения кассовой дисциплины и своевременного пробития чеков становится очень остро. Человеческий фактор в данном случае становится просто катастрофическим.

К сожалению, типовые конфигурации 1С нам не предлагают возможность вести учет z-отчетов, что ж, реализуем сами.

Внедрение бизнес процесса по контролю и учету z-отчетов можно разделить на три этапа:

1. Создание в 1С документа "z-отчет" с ручным вводом информации.
2. Контроль и формирование отчетов по проверке показателей, которые можно извлечь из Z-отчета.
3. Автоматизация загрузки с ККМ данных о z-отчетах (их автоматическое создание в 1С).

Маленькая ремарка: Предоставленная ниже реализация z-отчета, является решением во времена ККМ с ЭКЛЗ и плавно была трансформирована (с обратной совместимостью) в решение для онлайн касс.

ПРИСТУПИМ: 

1 ЭТАП

Создаем новый документ «_ZОтчетФискальный»
Реквизиты:
- Организация (СправочникСсылка.Организации)
- Подразделение (СправочникСсылка.Подразделения)
- ККМ (СправочникСсылка.КассыККМ)
- Накопление (Число15.2)  В новых он-лайн ККМ это поле теперь называется ГРОСС ИТОГ
- Выручка (Число15.2)
- Возвраты (Число15.2)
- ВыручкаБезТоварныхЧеков (Число15.2) В этом поле отражают выручку, регистрируемую при поступлении средств от «оптовых» покупателей (ТОРГ12+ПКО).
- Неиспользованные (Число15.2)
- НомерГашения (Число10.0) В новых он-лайн ККМ это поле теперь называется НОМЕР СМЕНЫ.
- СуммаДокумента (Число15.2)
Для отображения в журнале
- НачальныеСведения (Булево) Этот реквизит необходим для обозначения вноса первого
Z
-отчета ККМ, или при смене ФН. При его установке не проверяется хронология отчетов по ККМ.
- Ответственный (СправочникСсылка.Пользователи)
- Комментарий (Строка)


Z-Отчет. Вид из конфигуратора.

В модуле объекта пишем код для проверки заполнения при проведении документа.

Функция НайтиПредыдущееГашение() Экспорт
	СведенияОПредыдущем = Новый Структура("НомерГашения,Накопление,СсылкаНаДокумент");
	СведенияОПредыдущем.НомерГашения=Неопределено;
	СведенияОПредыдущем.Накопление=Неопределено;
	СведенияОПредыдущем.СсылкаНаДокумент=Неопределено;
	Если НЕ НачальныеСведения Тогда
		Запрос=Новый Запрос("ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 1 
		|Ссылка, 
		|Дата, 
		|Организация, 
		|ККМ, 
		|Накопление, 
		|НомерГашения,
		|Проведен
		|ИЗ Документ._ZОтчетФискальный
		|ГДЕ Дата<&ДатаКонец И Организация=&ВыбОрганизация И ККМ=&ВыбКасса И Проведен
		|УПОРЯДОЧИТЬ ПО Дата УБЫВ");
		Запрос.УстановитьПараметр("ВыбОрганизация",Организация);					
		Запрос.УстановитьПараметр("ВыбКасса",ККМ);					
		Запрос.УстановитьПараметр("ДатаКонец",Дата);					
		Выборка =  Запрос.Выполнить().Выбрать();
		Если Выборка.Следующий() Тогда
			СведенияОПредыдущем.НомерГашения=Выборка.НомерГашения;
			СведенияОПредыдущем.Накопление=Выборка.Накопление;
			СведенияОПредыдущем.СсылкаНаДокумент=Выборка.Ссылка;
		КонецЕсли;
	КонецЕсли;						
	Возврат СведенияОПредыдущем;
КонецФункции

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

Если вы обратили внимание, пользователь не может провести документ «_ZОтчетФискальный», если не выполняется математика или не соблюдается очередность отчетов.

Закомментированный код применялся при подсчете накопления в старых моделях ККМ с ЭКЛЗ, теперь в нем нет необходимости.

Документ «_ZОтчетФискальный» все проверки производит по указанной в документе конкретной кассе ККМ.

Небольшое лирическое отступление:

При эксплуатации касс АТОЛ 11Ф у нас неоднократно случались ошибки математики «ГРОСС ИТОГА» во время пробития z-отчета на ККМ, как правило при сбое (окончание бумаги или разряд аккумулятора).
Что ж, не беда, в нашем случае предусмотрен флаг «НачальныеСведения» в документе, при его установки документ позволяет начать отсчет номер гашения и накопление заново.

Вызов форма списка документа поместил в меню: Документы>Управление денежными средствами>Z-Отчеты

Форма списка выглядит так:

Форму документа я оформил в наглядном и понятном бухгалтеру виде:

Форма документа z-отчет в 1С

Код формы документа:

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

Процедура ОбновитьНадписиПриИзмененииЭлемента(Элемент)
	ОбновитьНадписи();
	ОбновитьОбразецЧека();
КонецПроцедуры

Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
	ДокументОбъект.СуммаДокумента=ДокументОбъект.Выручка-ДокументОбъект.Возвраты-ДокументОбъект.Неиспользованные;
КонецПроцедуры

Функция НайтиПредыдущееГашениеНаСервере() 
	Возврат НайтиПредыдущееГашение(); 
КонецФункции

Процедура ОбновитьНадписи()
	СведенияОПредыдущем= НайтиПредыдущееГашениеНаСервере();
	ЭлементыФормы.РамкаСтарыйОтчет.Видимость=ДокументОбъект.НачальныеСведения;
	Если СведенияОПредыдущем.НомерГашения=Неопределено Тогда
		ЭлементыФормы.ПРНомерГашения.Заголовок="Номер гашения: Нет сведений";
		ЭлементыФормы.ПРНакопление.Заголовок="Накопление: Нет сведений";
		ЭлементыФормы.ПРНомерГашения.Видимость = Ложь;
		ЭлементыФормы.ПРНакопление.Видимость = Ложь;
	Иначе
		ЭлементыФормы.ПРНомерГашения.Заголовок="Номер гашения: "+ФОРМАТ(СведенияОПредыдущем.НомерГашения,"ЧГ=");
		ЭлементыФормы.ПРНакопление.Заголовок="Накопление: "+ФОРМАТ(СведенияОПредыдущем.Накопление)+" руб.";
		ЭлементыФормы.ПРНомерГашения.Видимость = Истина;
		ЭлементыФормы.ПРНакопление.Видимость = Истина;
	КонецЕсли;
КонецПроцедуры

Процедура ОбновитьОбразецЧека()	
	ЭлементыФормы.ФД.Очистить();
	ЭлементыФормы.ФД.ДобавитьСтроку("ИНН "+ДокументОбъект.Организация.ИНН);
	ЭлементыФормы.ФД.ДобавитьСтроку("Z-ОТЧЕТ ФИСКАЛЬНЫЙ");
	ЭлементыФормы.ФД.ДобавитьСтроку("ККМ "+ДокументОбъект.ККМ.СерийныйНомер);
	ЭлементыФормы.ФД.ДобавитьСтроку("ЗАКР.СМЕНЫ  "+ПРАВ("0000"+ФОРМАТ(ДокументОбъект.НомерГашения,"ЧГ="),4));
	ЭлементыФормы.ФД.ДобавитьСтроку("");
	ЭлементыФормы.ФД.ДобавитьСтроку("НАКОПЛЕНИЕ");
	ЭлементыФормы.ФД.ДобавитьСтроку("ГРОСС-ИТОГ");
	ЭлементыФормы.ФД.ДобавитьСтроку("  "+ПРАВ("..........."+ФОРМАТ(ДокументОбъект.Накопление,"ЧЦ=15; ЧДЦ=2; ЧРД=.; ЧН=0.00; ЧГ="),15));
	ЭлементыФормы.ФД.ДобавитьСтроку("ВЫРУЧКА");
	ЭлементыФормы.ФД.ДобавитьСтроку("  "+ПРАВ("..........."+ФОРМАТ(ДокументОбъект.Выручка,"ЧЦ=15; ЧДЦ=2; ЧРД=.; ЧН=0.00; ЧГ="),15));
	ЭлементыФормы.ФД.ДобавитьСтроку(Формат(ДокументОбъект.Дата,"ДФ=""дд.ММ.гг ЧЧ.мм""")+"Ф");
	ЭлементыФормы.ФД.ДобавитьСтроку("ВОЗВРАТЫ");
	ЭлементыФормы.ФД.ДобавитьСтроку("  "+ПРАВ("..........."+ФОРМАТ(ДокументОбъект.Возвраты,"ЧЦ=15; ЧДЦ=2; ЧРД=.; ЧН=0.00; ЧГ="),15));
КонецПроцедуры

Если используете управляемые формы, то получать ИНН организации и серийный номер ККМ нужно через вызов функции на сервере.

 

2 ЭТАП

Создаем средства проверки и контроля данных в z-отчетах. Для этого у нас уже существует решение для бухгалтеров «ЕДИНАЯ ПРОВЕРКА ОШИБОК». Добавляем раздел по проверке сразу всех Z-отчетов, внесенных в 1С за определенный период.

Макет для вывода результатов проверки там выглядит как-то так:

Макет отчета

Создаем процедуры по проверке документов «_ZОтчетФискальный»:

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

ОШИБКИ:

- В Z-отчете указаны неиспользованные чеки, но при этом ПКО оформлен на всю сумму выручки в Z-отчете на дату ХХХ
- В Z-отчете указаны оптовые продажи, но при этом ПКО с видом ""Прием розничной выручки"" оформлен на всю сумму выручки в Z-отчете на дату ХХХ

- Чистая выручка по Z-отчету ХХХ не соответсвует сумме ПКО ХХХ по кассе ККМ ХХХ на дату ХХХ
- Сумма неиспользованных чеков и оптовых продаж превышает общую выручку
- Сумма опта Z-отчетов ХХХ по подразделению ХХХ не сходится с суммой ПКО ХХХ на дату ХХХ
-
Не найден предыдущий Финансовый отчет (гашение) для ККМ ХХХ
- Уже существует документ с таким номером гашения для выбранной ККМ. Возможно вы задублировали документ. Ожидается номер ХХХ
- Существует документ с более поздним номером гашения для выбранной ККМ. Отмените более поздние гашения, и проведите их в порядке возрастания номера гашения.  Ожидается номер ХХХ
- Существуют пропущенные номера гашения для выбранной ККМ. Преверте номер гашения или проведите гашения для пропущенных номеров. Ожидается номер ХХХ
- Контроль накопления не пройден! Проверьте правильность внесения данных с бумажного чека "Z-ОТЧЕТ (фискальный)"!

 

ПРЕДУПРЕЖДЕНИЯ:

- По кассе ККМ ХХХ на дату ХХХ должен быть оформлен акт по неиспользованным кассовым чекам(КМ-3) на сумму ХХХ
- По кассе ККМ ХХХ на дату ХХХ должен быть оформлено заявление на возврат на сумму ХХХ
- По кассе ККМ ХХХ найдено несколько Z-отчетов с признаком "Начальные сведения"

 

 

 
 Кто хочет посмотреть код проверок

 

Процедура ПроверкаZОтчетов(ТД,Макет)
	Запрос = Новый Запрос;
	Запрос.Текст = "ВЫБРАТЬ
	|	_ZОтчетФискальный.ККМ КАК ККМ,
	|	МИНИМУМ(_ZОтчетФискальный.Дата) КАК Дата
	|ИЗ
	|	Документ._ZОтчетФискальный КАК _ZОтчетФискальный
	|ГДЕ
	|	_ZОтчетФискальный.Дата >= &Дата1
	|
	|СГРУППИРОВАТЬ ПО
	|	_ZОтчетФискальный.ККМ";
	Запрос.Параметры.Вставить("Дата1",НачалоДня(ОбработкаОбъект.Период.ДатаНачала));
	ТаблицаКасс = Запрос.Выполнить().Выбрать();
	Пока ТаблицаКасс.Следующий() Цикл
		Запрос = Новый Запрос;
		Запрос.Текст="ВЫБРАТЬ
		|	ПКО.День КАК Дата,
		|	ЕСТЬNULL(ПКО.СуммаДокумента, 0) КАК СуммаПКО,
		|	ПКО.Контрагент КАК ККМ,
		|	ЕСТЬNULL(Отчеты.Выручка, 0) КАК СуммаОтчета,
		|	ЕСТЬNULL(Отчеты.Неиспользованные, 0) КАК Неиспользованные,
		|	ЕСТЬNULL(Отчеты.Возвраты, 0) КАК Возвраты,
		|	Отчеты.День КАК ДатаОтчета,
		|	Отчеты.ККМ КАК ККМОтчета,
		|	ЕСТЬNULL(Отчеты.ВыручкаБезТоварныхЧеков, 0) КАК Опт,
		|	ЕСТЬNULL(Отчеты.ВыручкаЧистая, 0) КАК СуммаОтчетаЧистая
		|ИЗ
		|	(ВЫБРАТЬ
		|		_ZОтчетФискальный.Организация КАК Организация,
		|		_ZОтчетФискальный.ККМ КАК ККМ,
		|		СУММА(_ZОтчетФискальный.Выручка) КАК Выручка,
		|		НАЧАЛОПЕРИОДА(_ZОтчетФискальный.Дата, ДЕНЬ) КАК День,
		|		СУММА(_ZОтчетФискальный.Неиспользованные) КАК Неиспользованные,
		|		СУММА(_ZОтчетФискальный.Возвраты) КАК Возвраты,
		|		СУММА(_ZОтчетФискальный.ВыручкаБезТоварныхЧеков) КАК ВыручкаБезТоварныхЧеков,
		|		СУММА(_ZОтчетФискальный.Выручка - _ZОтчетФискальный.Неиспользованные -  _ZОтчетФискальный.ВыручкаБезТоварныхЧеков) КАК ВыручкаЧистая
		|	ИЗ
		|		Документ._ZОтчетФискальный КАК _ZОтчетФискальный
		|	ГДЕ
		|		_ZОтчетФискальный.Дата МЕЖДУ &Дата1 И &Дата2
		|		И _ZОтчетФискальный.Проведен = ИСТИНА
		|		И _ZОтчетФискальный.Организация = &Организация
		|		И _ZОтчетФискальный.ККМ = &ККМ
		|	
		|	СГРУППИРОВАТЬ ПО
		|		_ZОтчетФискальный.Организация,
		|		_ZОтчетФискальный.ККМ,
		|		НАЧАЛОПЕРИОДА(_ZОтчетФискальный.Дата, ДЕНЬ)) КАК Отчеты
		|		ПОЛНОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
		|			ПриходныйКассовыйОрдер.Организация КАК Организация,
		|			ПриходныйКассовыйОрдер.Контрагент КАК Контрагент,
		|			СУММА(ПриходныйКассовыйОрдер.СуммаДокумента) КАК СуммаДокумента,
		|			НАЧАЛОПЕРИОДА(ПриходныйКассовыйОрдер.Дата, ДЕНЬ) КАК День
		|		ИЗ
		|			Документ.ПриходныйКассовыйОрдер КАК ПриходныйКассовыйОрдер
		|		ГДЕ
		|			ПриходныйКассовыйОрдер.Проведен = ИСТИНА
		|			И ПриходныйКассовыйОрдер.Дата МЕЖДУ &Дата1 И &Дата2
		|			И ПриходныйКассовыйОрдер.Организация = &Организация
		|			И ТИПЗНАЧЕНИЯ(ПриходныйКассовыйОрдер.Контрагент) = ТИП(Справочник.КассыККМ)
		|			И ПриходныйКассовыйОрдер.ВидОперации = ЗНАЧЕНИЕ(Перечисление.ВидыОперацийПКО.ПриходДенежныхСредствРозничнаяВыручка)
		|			И ПриходныйКассовыйОрдер.ОтражатьВБухгалтерскомУчете = ИСТИНА
		|			И ПриходныйКассовыйОрдер.Контрагент = &ККМ
		|		
		|		СГРУППИРОВАТЬ ПО
		|			ПриходныйКассовыйОрдер.Организация,
		|			ПриходныйКассовыйОрдер.Контрагент,
		|			НАЧАЛОПЕРИОДА(ПриходныйКассовыйОрдер.Дата, ДЕНЬ)) КАК ПКО
		|		ПО Отчеты.Организация = ПКО.Организация
		|			И Отчеты.ККМ = ПКО.Контрагент
		|			И Отчеты.День = ПКО.День";
		Запрос.УстановитьПараметр("Организация",ОбработкаОбъект.Организация);					
		Запрос.УстановитьПараметр("Дата1",?(ТаблицаКасс.Дата>ОбработкаОбъект.Период.ДатаНачала,НачалоДня(ТаблицаКасс.Дата),НачалоДня(ОбработкаОбъект.Период.ДатаНачала)));					
		Запрос.УстановитьПараметр("Дата2",КонецДня(ОбработкаОбъект.Период.ДатаОкончания));
		Запрос.УстановитьПараметр("ККМ",ТаблицаКасс.ККМ);
		Выборка = Запрос.Выполнить().Выбрать();
		Пока Выборка.Следующий() Цикл
			Если Выборка.СуммаПКО = Выборка.СуммаОтчета И Выборка.Неиспользованные >0 Тогда			
				ОбластьМакета         = Макет.ПолучитьОбласть("Ошибка");
				ОбластьМакета.Параметры.ОбъектаПроверки        =?(Выборка.ККМ = Null,Выборка.ККМОтчета,Выборка.ККМ);
				ОбластьМакета.Параметры.Ошибка				   ="В Z-отчете указаны неиспользованные чеки, но при этом ПКО оформлен на всю сумму выручки в Z-отчете на дату: " + Формат(?(Выборка.Дата = Null,Выборка.ДатаОтчета,Выборка.Дата),"ДФ=dd.MM.yy; ДЛФ=D");
				ТД.Вывести(ОбластьМакета);
			КонецЕсли;
				Если Выборка.СуммаПКО = Выборка.СуммаОтчета И Выборка.Опт >0 Тогда			
				ОбластьМакета         = Макет.ПолучитьОбласть("Ошибка");
				ОбластьМакета.Параметры.ОбъектаПроверки        =?(Выборка.ККМ = Null,Выборка.ККМОтчета,Выборка.ККМ);
				ОбластьМакета.Параметры.Ошибка				   ="В Z-отчете указаны оптовые продажи, но при этом ПКО с видом ""Прием розничной выручки"" оформлен на всю сумму выручки в Z-отчете на дату: " + Формат(?(Выборка.Дата = Null,Выборка.ДатаОтчета,Выборка.Дата),"ДФ=dd.MM.yy; ДЛФ=D");
				ТД.Вывести(ОбластьМакета);
			КонецЕсли;
			Если Выборка.СуммаПКО <> Выборка.СуммаОтчетаЧистая Тогда			
				ОбластьМакета         = Макет.ПолучитьОбласть("Ошибка");
				ОбластьМакета.Параметры.ОбъектаПроверки        =?(Выборка.ККМ = Null,Выборка.ККМОтчета,Выборка.ККМ);
				ОбластьМакета.Параметры.Ошибка				   ="Чистая выручка по Z-отчету: "+Выборка.СуммаОтчетаЧистая+" не соответсвует сумме ПКО: "+Выборка.СуммаПКО+" по кассе ККМ: "+Выборка.ККМ+" на дату: "+Формат(?(Выборка.Дата = Null,Выборка.ДатаОтчета,Выборка.Дата),"ДФ=dd.MM.yy; ДЛФ=D");
				ТД.Вывести(ОбластьМакета);
			КонецЕсли;
			Если Выборка.Неиспользованные>0 Тогда
				ОбластьМакета         = Макет.ПолучитьОбласть("Предупреждение");
				ОбластьМакета.Параметры.ОбъектаПроверки        =?(Выборка.ККМ = Null,Выборка.ККМОтчета,Выборка.ККМ);
				ОбластьМакета.Параметры.Ошибка				   ="По кассе ККМ: "+?(Выборка.ККМ = Null,Выборка.ККМОтчета,Выборка.ККМ)+" на дату: "+Формат(?(Выборка.Дата = Null,Выборка.ДатаОтчета,Выборка.Дата),"ДФ=dd.MM.yy; ДЛФ=D") + " должен быть оформлен акт по неиспользованным кассовым чекам(КМ-3) на сумму " + Выборка.Неиспользованные;
				ТД.Вывести(ОбластьМакета);
			КонецЕсли;	
			Если Выборка.Возвраты>0 Тогда
				ОбластьМакета         = Макет.ПолучитьОбласть("Предупреждение");
				ОбластьМакета.Параметры.ОбъектаПроверки        =?(Выборка.ККМ = Null,Выборка.ККМОтчета,Выборка.ККМ);
				ОбластьМакета.Параметры.Ошибка				   ="По кассе ККМ: "+?(Выборка.ККМ = Null,Выборка.ККМОтчета,Выборка.ККМ)+" на дату: "+Формат(?(Выборка.Дата = Null,Выборка.ДатаОтчета,Выборка.Дата),"ДФ=dd.MM.yy; ДЛФ=D") + " должен быть оформлено заявление на возврат на сумму " + Выборка.Возвраты;
				ТД.Вывести(ОбластьМакета);
			КонецЕсли;	
		КонецЦикла;
		Запрос = Новый Запрос;
		ЕстьНачальный = Ложь;
		Запрос.Текст="ВЫБРАТЬ
		|	_ZОтчетФискальный.Ссылка КАК Ссылка,
		|	_ZОтчетФискальный.НачальныеСведения КАК НачальныеСведения
		|ИЗ
		|	Документ._ZОтчетФискальный КАК _ZОтчетФискальный
		|ГДЕ
		|	_ZОтчетФискальный.ККМ = &ККМ
		|	И _ZОтчетФискальный.Дата МЕЖДУ &Дата1 И &Дата2
		|	И _ZОтчетФискальный.Проведен = ИСТИНА
		|	И _ZОтчетФискальный.Организация = &Организация";
		Запрос.УстановитьПараметр("Дата1",?(ТаблицаКасс.Дата>ОбработкаОбъект.Период.ДатаНачала,НачалоДня(ТаблицаКасс.Дата),НачалоДня(ОбработкаОбъект.Период.ДатаНачала)));					
		Запрос.УстановитьПараметр("Дата2",КонецДня(ОбработкаОбъект.Период.ДатаОкончания));
		Запрос.УстановитьПараметр("ККМ",ТаблицаКасс.ККМ);
		Запрос.УстановитьПараметр("Организация",ОбработкаОбъект.Организация);
		ZОтчеты = Запрос.Выполнить().Выбрать();
		Пока ZОтчеты.Следующий() Цикл
			Если ЕстьНачальный И ZОтчеты.НачальныеСведения Тогда
				ОбластьМакета         = Макет.ПолучитьОбласть("Предупреждение");
				ОбластьМакета.Параметры.ОбъектаПроверки        =?(Выборка.ККМ = Null,Выборка.ККМОтчета,Выборка.ККМ);
				ОбластьМакета.Параметры.Ошибка				   ="По кассе ККМ " + ?(Выборка.ККМ = Null,Выборка.ККМОтчета,Выборка.ККМ) + " найдено несколько Z-отчетов с признаком ""Начальные сведения""";
				ТД.Вывести(ОбластьМакета);
			КонецЕсли;
			Если ZОтчеты.НачальныеСведения Тогда
				ЕстьНачальный = Истина;
			КонецЕсли;
			ПроверкаКорректностиZОтчетов(ZОтчеты.Ссылка,Выборка.ККМ,ТД,Макет);
		КонецЦикла;
	КонецЦикла;
	Запрос = Новый Запрос;
	Запрос.Текст = "ВЫБРАТЬ
	|	МИНИМУМ(_ZОтчетФискальный.Дата) КАК Дата,
	|	_ZОтчетФискальный.ККМ.ПодразделениеОрганизации КАК Подразделение
	|ИЗ
	|	Документ._ZОтчетФискальный КАК _ZОтчетФискальный
	|ГДЕ
	|	_ZОтчетФискальный.Дата >= &Дата1
	|
	|СГРУППИРОВАТЬ ПО
	|	_ZОтчетФискальный.ККМ.ПодразделениеОрганизации";
	Запрос.Параметры.Вставить("Дата1",НачалоДня(ОбработкаОбъект.Период.ДатаНачала));
	ТаблицаПодразделений = Запрос.Выполнить().Выбрать();
	Пока ТаблицаПодразделений.Следующий() Цикл
		ЗапросОпт = Новый Запрос;
		ЗапросОпт.Текст = "ВЫБРАТЬ
		|	ПКО.День КАК Дата,
		|	ЕСТЬNULL(ПКО.СуммаДокумента, 0) КАК СуммаПКО,
		|	Отчеты.День КАК ДатаОтчета,
		|	ЕСТЬNULL(Отчеты.ВыручкаБезТоварныхЧеков, 0) КАК Опт,
		|	Отчеты.Подразделение,
		|	ПКО.Подразделение КАК ПодразделениеПКО
		|ИЗ
		|	(ВЫБРАТЬ
		|		_ZОтчетФискальный.Организация КАК Организация,
		|		НАЧАЛОПЕРИОДА(_ZОтчетФискальный.Дата, ДЕНЬ) КАК День,
		|		СУММА(_ZОтчетФискальный.ВыручкаБезТоварныхЧеков) КАК ВыручкаБезТоварныхЧеков,
		|		_ZОтчетФискальный.Подразделение КАК Подразделение
		|	ИЗ
		|		Документ._ZОтчетФискальный КАК _ZОтчетФискальный
		|	ГДЕ
		|		_ZОтчетФискальный.Дата МЕЖДУ &Дата1 И &Дата2
		|		И _ZОтчетФискальный.Проведен = ИСТИНА
		|		И _ZОтчетФискальный.Организация = &Организация
		|		И _ZОтчетФискальный.ВыручкаБезТоварныхЧеков > 0
		|		И _ZОтчетФискальный.Подразделение = &Подразделение
		|	
		|	СГРУППИРОВАТЬ ПО
		|		_ZОтчетФискальный.Организация,
		|		НАЧАЛОПЕРИОДА(_ZОтчетФискальный.Дата, ДЕНЬ),
		|		_ZОтчетФискальный.Подразделение) КАК Отчеты
		|		ПОЛНОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
		|			ПриходныйКассовыйОрдер.Организация КАК Организация,
		|			СУММА(ПриходныйКассовыйОрдер.СуммаДокумента) КАК СуммаДокумента,
		|			НАЧАЛОПЕРИОДА(ПриходныйКассовыйОрдер.Дата, ДЕНЬ) КАК День,
		|			ПриходныйКассовыйОрдер.Подразделение КАК Подразделение
		|		ИЗ
		|			Документ.ПриходныйКассовыйОрдер КАК ПриходныйКассовыйОрдер
		|		ГДЕ
		|			ПриходныйКассовыйОрдер.Проведен = ИСТИНА
		|			И ПриходныйКассовыйОрдер.Дата МЕЖДУ &Дата1 И &Дата2
		|			И ПриходныйКассовыйОрдер.Организация = &Организация
		|			И ПриходныйКассовыйОрдер.ВидОперации = ЗНАЧЕНИЕ(Перечисление.ВидыОперацийПКО.ОплатаПокупателя)
		|			И ПриходныйКассовыйОрдер.ОтражатьВБухгалтерскомУчете = ИСТИНА
		|			И ПриходныйКассовыйОрдер.Подразделение = &Подразделение
		|		
		|		СГРУППИРОВАТЬ ПО
		|			ПриходныйКассовыйОрдер.Организация,
		|			НАЧАЛОПЕРИОДА(ПриходныйКассовыйОрдер.Дата, ДЕНЬ),
		|			ПриходныйКассовыйОрдер.Подразделение) КАК ПКО
		|		ПО Отчеты.Организация = ПКО.Организация
		|			И Отчеты.День = ПКО.День
		|			И Отчеты.Подразделение = ПКО.Подразделение";
		ЗапросОпт.УстановитьПараметр("Организация",ОбработкаОбъект.Организация);					
		ЗапросОпт.УстановитьПараметр("Дата1",?(ТаблицаКасс.Дата>ОбработкаОбъект.Период.ДатаНачала,НачалоДня(ТаблицаКасс.Дата),НачалоДня(ОбработкаОбъект.Период.ДатаНачала)));					
		ЗапросОпт.УстановитьПараметр("Дата2",КонецДня(ОбработкаОбъект.Период.ДатаОкончания));
		ЗапросОпт.УстановитьПараметр("Подразделение",ПодразделениеОрганизацииВПодразделение(ТаблицаПодразделений.Подразделение));
		ВыборкаОпт = ЗапросОпт.Выполнить().Выбрать();
		Пока ВыборкаОпт.Следующий() Цикл
			Если ВыборкаОпт.Опт <> ВыборкаОпт.СуммаПКО Тогда
				ОбластьМакета         = Макет.ПолучитьОбласть("Ошибка");
				ОбластьМакета.Параметры.ОбъектаПроверки        =?(ВыборкаОпт.Подразделение = Null,ВыборкаОпт.ПодразделениеПКО,ВыборкаОпт.Подразделение);
				ОбластьМакета.Параметры.Ошибка				   ="Сумма опта Z-отчетов: " + ВыборкаОпт.Опт + " по подразделению " + ?(ВыборкаОпт.Подразделение = Null,ВыборкаОпт.ПодразделениеПКО,ВыборкаОпт.Подразделение) + " не сходится с суммой ПКО: " + ВыборкаОпт.СуммаПКО + " на дату " + Формат(?(ВыборкаОпт.Дата = Null,ВыборкаОпт.ДатаОтчета,ВыборкаОпт.Дата),"ДФ=dd.MM.yy; ДЛФ=D");
				ТД.Вывести(ОбластьМакета);
			КонецЕсли;	
		КонецЦикла;
	КонецЦикла;	
КонецПроцедуры

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

Функция ПодразделениеОрганизацииВПодразделение(ПодразделениеОрганизации) Экспорт
	    Запрос=Новый запрос;
		Запрос.Текст=
		"ВЫБРАТЬ РАЗРЕШЕННЫЕ
		|	СоответствиеПодразделенийИПодразделенийОрганизаций.Подразделение,
		|	СоответствиеПодразделенийИПодразделенийОрганизаций.ПодразделениеОрганизации
		|ИЗ
		|	РегистрСведений.СоответствиеПодразделенийИПодразделенийОрганизаций КАК СоответствиеПодразделенийИПодразделенийОрганизаций
		|ГДЕ
		|	СоответствиеПодразделенийИПодразделенийОрганизаций.ПодразделениеОрганизации = &ПодразделениеОрганизации
		|	И СоответствиеПодразделенийИПодразделенийОрганизаций.Организация = &Организация";
		
		Запрос.УстановитьПараметр("ПодразделениеОрганизации",ПодразделениеОрганизации);
		Запрос.УстановитьПараметр("Организация",ПодразделениеОрганизации.Владелец);
		
		Результат=Запрос.Выполнить().Выбрать();
		Если Результат.Следующий() Тогда
			Возврат  Результат.Подразделение;
		КонецЕсли;
		Возврат Справочники.Подразделения.ПустаяСсылка();

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



 

 

В результате можно формировать отчеты по проверки z- отчетов за любой период и вовремя устранять нарушения, не дожидаясь того, что на эти ошибки укажет вам ФНС.

Пример работы проверки:

Единая проверка ошибок

 

3 ЭТАП

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

Рассмотрим на примере POS систем АТОЛ и их ККМ.

Стандартный обмен текстовыми файлами с POS системами АТОЛ нам не особо помогает в процессе автоматизации.
При пробитии z-отчета POS система АТОЛа пишет в файл report.txt  строку с кодом "63"
Пример строки:

 

1937;19.04.2018;20:09:47;63;1;195;2;;19;1379;1379;1379;9;2;0;0;0;;;1379;;0;8;0;;146/245/19;1;;;;;;;0;0 - Ошибок нет,0 - Ошибок нет,0 - Ошибок нет;;;;;;;; 

Что можно из нее выдернуть :
дата - 19.04.2018,
время – 20:09:47
порядковый номер
z
-отчета -  19
выручку -1379.00
наличную часть выручки – 1379.00
накопление (ГРОСС ИТОГ) – такой информации АТОЛ в файл не записывает.

АТОЛ дает обработку «82АТОЛ.epf». В ее модуле объекта можно найти участок кода:

Функция ПрочитатьФайлВыгрузки(Объект, Файл, Отчет, Карты, Оплаты)
//++Комментарий автора
// Эта функция вызывается из Функции ЗагрузитьОтчет(Объект, Отчет, Карты = Неопределено, Оплаты = Неопределено)
// А она вызывается из функции «ЗагрузитьОтчетОПродажах» обработки конфигурации «ТОСервер»
//--Комментарий автора
       //… разбор файла и запись его в таблицу «Отчет»…

		ИначеЕсли ТипТранзакции = 63 Тогда
			// Z-отчёт
			Если Объект.Параметры.КритичныеОперации Тогда
				Попытка
					НомерСмены		= Число(СтрПолучитьСтроку(ТекущаяСтрока, 9));
					Выручка		= Число(СтрПолучитьСтроку(ТекущаяСтрока, 10));
					Наличность	= Число(СтрПолучитьСтроку(ТекущаяСтрока, 11));
					СменныйИтог = Число(СтрПолучитьСтроку(ТекущаяСтрока, 12));

				Исключение
				КонецПопытки;
			КонецЕсли;

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

Для автоматизации загрузки Z-отчетов нужно передать по функциям пустую табличку с полями z-отчета и заполнить ее в указанном участке кода, а по возврату таблицы из функций - создать документ _ZОтчетФискальный в  модуле обработки «ТОСервер».

Нам этот способ не подходил, поскольку АТОЛ не выдает накопление (ГРОСС ИТОГ) и возвраты, а их проверка была жизненно необходима.

Мы пошли другим путем, написали свою POS  систему и сведения брали из драйвера ККМ в полном объеме в виде XML.

Пример xml

О обработках по автоматической загрузке данных с ККМ в 1С парсим приходящие файлы XML от ККМ.

Функция ЗагрузитьXML_reg(ПолноеИмяФайла) Экспорт    
	Перем ПостроитьДУМ,ДокументДУМ;
	ПостроитьДУМ = Новый ПостроительDOM; 
	ПолучитьКорневойУзелXMLФайла(ПолноеИмяФайла,ПостроитьДУМ,ДокументДУМ);
	Если ДокументДУМ=Неопределено Тогда
		Возврат Ложь;
	КонецЕсли;
	КорневойУзел = ДокументДУМ.ПервыйДочерний;
	Если КорневойУзел=Неопределено Тогда
		Возврат Истина;
	КонецЕсли;
	
//...
	ЕстьОшибки = Ложь;
	Если КорневойУзел.ЕстьДочерниеУзлы() Тогда
		Для Каждого Узел_entry ИЗ КорневойУзел.ПолучитьЭлементыПоИмени("Документы") Цикл
			Если Узел_entry.ЕстьДочерниеУзлы() Тогда
//…
				Для Каждого Узел_requests ИЗ Узел_entry.ПолучитьЭлементыПоИмени("Документ.ZОтчёт") Цикл  //ZОтчет
					СтруктураДок = Новый Структура("ИДОтчета,НомерГашения,НомерСмены,ДатаККМ,НомерККМ,СуммаВыручки,СуммаВозвратов,СуммаВКассе,СуммаПрихода,СуммаНеобнуляемая","",0,0,Дата(1,1,1),"",0,0,0,0,0);
					Для Каждого УзелРеквизитЭлемента ИЗ Узел_requests.ПолучитьЭлементыПоИмени("*") Цикл
						ТекИмяУзла = УзелРеквизитЭлемента.ИмяУзла;
						ТекЗначениеУзла = СокрЛП(УзелРеквизитЭлемента.ТекстовоеСодержимое);
						Если ТекИмяУзла="ДатаККМ"  Тогда
							СтруктураДок.Вставить(ТекИмяУзла,ПолучитьДатуВремяИзСтроки(ТекЗначениеУзла,6)); 
						ИначеЕсли ТекИмяУзла="СуммаВыручки" ИЛИ ТекИмяУзла="СуммаВозвратов" ИЛИ  ТекИмяУзла="СуммаВКассе" ИЛИ  ТекИмяУзла="СуммаПрихода" ИЛИ  ТекИмяУзла="СуммаНеобнуляемая" Тогда
							СтруктураДок.Вставить(ТекИмяУзла,Число(ТекЗначениеУзла));
						Иначе
							СтруктураДок.Вставить(ТекИмяУзла,СокрЛП(ТекЗначениеУзла));
						КонецЕсли;
					КонецЦикла;//конец шапки документа
					НовЧек = ZОтчет.Добавить();
					НовЧек.ИДОтчета				=СтруктураДок.ИДОтчета;
					НовЧек.НомерГашения			=СтруктураДок.НомерГашения;
					НовЧек.НомерСмены			=СтруктураДок.НомерСмены;
					НовЧек.ДатаККМ				=СтруктураДок.ДатаККМ;
					НовЧек.НомерККМ				=СтруктураДок.НомерККМ;
					НовЧек.СуммаВыручки			=СтруктураДок.СуммаВыручки;
					НовЧек.СуммаВозвратов		=СтруктураДок.СуммаВозвратов;
					НовЧек.СуммаВКассе			=СтруктураДок.СуммаВКассе;
					НовЧек.СуммаПрихода			=СтруктураДок.СуммаПрихода;
					НовЧек.СуммаНеобнуляемая	=СтруктураДок.СуммаНеобнуляемая;
					НовЧек.СсылкаZОтчета		= ПолучитьДокZОтчетПоИД(СтруктураДок.ИдОтчета, СтруктураДок.ДатаККМ);
				КонецЦикла;
			КонецЕсли;
			
		КонецЦикла;
	КонецЕсли;
	
	
	Возврат ЕстьОшибки;
КонецФункции

Отдельно загружает загруженную таблицу z-отчетов

Функция ПолучитьКассуККМПоСерийномуНомеру(СерНомер)
	Запрос = новый Запрос;
	Запрос.УстановитьПараметр("СерНомер", СерНомер);
	Запрос.Текст= "ВЫБРАТЬ РАЗРЕШЕННЫЕ
	|	КассыККМ.Ссылка
	|ИЗ
	|	Справочник.КассыККМ КАК КассыККМ
	|ГДЕ
	|	КассыККМ.СерийныйНомер = &СерНомер";
	Выборка = Запрос.Выполнить().Выбрать();
	Если Выборка.Количество() = 0 тогда 
		Сообщить("Не удалось найти кассу с серийным номером " + СерНомер +" !!!");
		Возврат Неопределено;
	ИначеЕсли Выборка.Количество() > 1 тогда 
		ТекстЗаголовок = "В базе найдено две Кассы с одинаковым серийным номером"; 
		Сообщить(ТекстЗаголовок);
		Возврат Неопределено;
	ИначеЕсли Выборка.Количество() = 1 тогда 
		Выборка.Следующий();
		
		Возврат Выборка.Ссылка;
	КонецЕсли;	
	
КонецФункции	

Функция ПроверитьПервыйВвод(КассаККМ)
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("ККМ", КассаККМ);
	Запрос.Текст= "ВЫБРАТЬ
	|	_ZОтчетФискальный.Ссылка
	|ИЗ
	|	Документ._ZОтчетФискальный КАК _ZОтчетФискальный
	|ГДЕ
	|	_ZОтчетФискальный.ККМ = &ККМ
	|	И _ZОтчетФискальный.Проведен
	|	И НЕ _ZОтчетФискальный.ПометкаУдаления";
	Выборка = Запрос.Выполнить().Выбрать();			  
	Возврат НЕ Выборка.Следующий();			  
КонецФункции	

Процедура СоздатьДокументыZОтчеты(Кнопка)
	// Вставить содержимое обработчика.
	Если ZОтчет.Количество() = 0 тогда 
		Сообщить("Нет Z-Отчетов доступных для загрузки");
	КонецЕсли;
	ДЛя Каждого Ст Из ZОтчет Цикл 
		Если Ст.СоздатьZ тогда 
			ДокZ = Документы._ZОтчетФискальный.СоздатьДокумент();
			ЗаполнениеДокументов.ЗаполнитьШапкуДокумента(ДокZ);
			ДокZ.Дата = Ст.ДатаККМ;
			//Проверим организации
			Если ДокZ.Организация.Пустая() тогда 
				Организация = Справочники.Организации.НайтиПоКоду("000000001");
				Если Организация = Неопределено тогда 
					Сообщить("Не удалось установить организацию");
					Возврат;
				КонецЕсли;
				ДокZ.Организация = Организация;
			КонецЕсли;
			КассаККМ = ПолучитьКассуККМПоСерийномуНомеру(Ст.НомерККМ);
			Если не КассаККМ = Неопределено тогда 
				ДокZ.ККМ = КассаККМ;
			Иначе
				Возврат;
			КонецЕсли;
			
			Если ДокZ.Ответственный.Пустая() Тогда 
				ДокZ.Ответственный = ПараметрыСеанса.ТекущийПользователь;
			КонецЕсли;
			ДокZ.НачальныеСведения = ПроверитьПервыйВвод(ДокZ.ККМ);
			ДокZ.Подразделение = Подразделение;
			ДокZ.Возвраты 		= Ст.СуммаВозвратов;
			ДокZ.Выручка  		= Ст.СуммаВыручки;
			ДокZ.Накопление 	= Ст.СуммаНеобнуляемая;
			ДокZ.НомерГашения   = Ст.НомерСмены;
			ДокZ.СуммаДокумента =ДокZ.Выручка-ДокZ.Возвраты-ДокZ.Неиспользованные;
			ДокZ.Комментарий    = "АвтоСоздание ##"+Ст.ИДОтчета+"##";  
			Попытка
				ДокZ.Записать(РежимЗаписиДокумента.Проведение);
				Ст.СоздатьZ = Ложь;
			Исключение
				Сообщить("Документ не удалось записать и провести!!! " + ОписаниеОшибки());
				ДокZ.Записать(РежимЗаписиДокумента.Запись);
				Ст.СоздатьZ = Ложь;
			КонецПопытки; 
			Ст.СсылкаZОтчета = ДокZ.Ссылка;
		КонецЕсли;	
	КонецЦикла;		
	
КонецПроцедуры

 

В РЕЗУЛЬТАТЕ:

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

Настало время переходить на сверку данных не с ККМ, а с ОФД. Но это тема уже для следующих статей.

z-отчет ККМ проверка чеков

См. также

ККТ-ОНЛАЙН 54-ФЗ: Обработка для работы онлайн касс АТОЛ, ШТРИХ, VIKI PRINT и т.д. МАРКИРОВКА (Разрешит. режим) + ЭКВАЙРИНГ + БЕСПЛАТНЫЙ ДЕМО

ККМ Кассовые операции Розничная торговля Платформа 1С v8.3 1С:Комплексная автоматизация 1.х 1С:Бухгалтерия 2.0 1С:Управление торговлей 10 1С:Розница 2 1С:Управление производственным предприятием 1С:Бухгалтерия государственного учреждения 1С:Бухгалтерия 1.6 1С:Бухгалтерия автономного учреждения 1С:CRM ПРОФ, КОРП Россия Платные (руб)

Универсальная обработка для обслуживания любых фискальных регистраторов (ККТ), в том числе Веб сервер АТОЛ. Работает в соответствии с 54-ФЗ. (ФФД 1.0, ФФД 1.05, ФФД 1.1). Подключайте любую онлайн кассу к практически любой конфигурации. Нет необходимости обновлять 1С. Можно бесплатно скачать и протестировать. Может работать одновременно с несколькими онлайн-кассами, либо одной с разных рабочих мест. (через RDP, TCP\IP или веб-сервер) Позволяет разделить один чек сразу на несколько ККТ или на несколько систем налогообложения. Поддерживает разрешительный режим. Можно настроить собственный шаблонов чека. Можно использовать эквайринг там, где он не поддерживается. Работает на LINUX и Windows ЭМУЛЯТОР + ЭКВАЙРИНГ + МАРКИРОВКА + ПОДДЕРЖКА ФФД 1.2

6000 руб.

27.02.2017    766853    4690    9502    

2792

54-ФЗ и Разрешительный режим. Обработки для подключения онлайн-касс к 1С 8 (поддержка Маркировки) + Эмулятор + ФФД 1.2

ККМ Кассовые операции Розничная торговля Платформа 1С v8.3 1С:Комплексная автоматизация 1.х 1С:Бухгалтерия 2.0 1С:Управление торговлей 10 1С:Розница 2 1С:Управление производственным предприятием 1С:Бухгалтерия государственного учреждения 1С:Бухгалтерия автономного учреждения Россия Платные (руб)

Обработка осуществляет обслуживание ККТ АТОЛ, Штрих и Меркурий для конфигураций "УТ 10.3", "КА 1.1", "УПП 1.3", "Розница 1.0", "БП 2.0" и других отраслевых решений, построенных на основе указанных выше конфигурациях. Поддерживает возможность параллельно пробития чеков на одной ККМ несколькими пользователями. Поддерживает Веб-сервер Атол. Соответствует требованиям 54-ФЗ. Поддерживает ФФД 1.0, 1.05, 1.1 и 1.2. Разделяет чеки по нескольким СНО. Поддерживает механизмы подключения ККТ по TCP/IP, для работы через RDP или интернет. Поддержка маркировки и разрешительного режима.

5400 руб.

25.05.2015    318267    1852    3013    

998

Печать кассовых чеков на одну ККМ с нескольких рабочих мест для 1С:УТ11.х, КА2.х, Розница 2.х, УНФ, ERP 2.х, БП 3, БГУ2

ККМ Кассовые операции Розничная торговля Обмен с ГосИС Бухгалтерский учет Оперативный учет Управляемые формы 1С:Розница 2 1С:Управление нашей фирмой 1.6 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 1С:Розница 3.0 Платные (руб)

Расширение конфигурации для УТ 11.4, 11.5, КА 2.4, 2.5, Розница 3.0, 2.3 и 2.2, УНФ 1.6, УНФ 3x, ERP 2.4, 2.5, БП 3, БГУ2 (Управляемые формы) позволяет выполнять печать кассовых чеков на одну ККМ 54-ФЗ с нескольких рабочих мест. НИКАКИХ НАСТРОЕК В РАЗРАБОТКЕ - ПОДКЛЮЧИЛ И ПЕЧАТАЙ. Если у вас несколько отделов и одна ККМ - печатайте на одной ККМ! Если у вас две ККМ и одна поломалась - печатайте на одной ККМ, пока ремонтируете другую!

4000 руб.

27.08.2018    117001    994    565    

835

Загрузка чеков ФНС в документы 1С:БП, 1С:УНФ, 1С:ERP, 1С:КА и 1С:УТ

Кассовые операции Файловый обмен (TXT, XML, DBF), FTP ЭДО и ОФД Платформа 1С v8.3 Бухгалтерский учет 1С:Управление нашей фирмой 1.6 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 Россия Бухгалтерский учет Налоговый учет Управленческий учет Платные (руб)

В публикации размещены специализированные обработки для загрузки чеков в базах 1С (для локальных баз): '1С:Бухгалтерия предприятия, ред. 3.0', '1С:Управление нашей фирмой 8, ред. 3.0', '1С:Комплексная автоматизация, ред. 2.5', ‘1С:ERP Управление предприятием, ред. 2’ и ‘1С:Управление торговлей, ред. 11.5’. Вы просто сканируете QR коды с бумажных и электронных чеков c помощью мобильного приложения ФНС и чеки автоматически (без ручного ввода) загружаются в документы 'Авансовый отчет', 'Расходы предпринимателя', 'Путевой лист', 'Приходная накладная', 'Поступление (акты, накладные, УПД)', 'Приобретение товаров и услуг', 'Отчет о розничных продажах' и 'Поступление денежных документов'.

12960 руб.

19.08.2020    65344    304    73    

211

Обмен между 1С:Розница и Frontol 6 по организациям (Розница - Фронтол)

ККМ Розничная торговля Платформа 1С v8.3 Оперативный учет 1С:Розница 2 1С:Управление нашей фирмой 3.0 1С:Розница 3.0 Россия Бухгалтерский учет Управленческий учет Платные (руб)

Обмен между 1С:Розница и Frontol 6 при торговле от нескольких организаций, а также ряд других полезных функций. Данный модуль незаменим для тех, кто ведёт учет по нескольким организациям в 1С:Розница, а на РМК (рабочее место кассира) установлен Frontol, или планируется его установка. Подходит для 1С:Розница 2.3./ 3.0, 1С:УНФ 3.0

1500 руб.

22.03.2019    79065    403    476    

167

Загрузка в 1С:Бухгалтерию 3.0, 1С:КА 2.4, 2.5, УНФ 1.6/3.0 данных из ОФД о денежных поступлениях (чеках)

Кассовые операции ЭДО и ОФД Платформа 1С v8.3 Бухгалтерский учет 1С:Управление нашей фирмой 1.6 1С:Бухгалтерия 3.0 1С:Комплексная автоматизация 2.х Россия Бухгалтерский учет Платные (руб)

Согласно 54-ФЗ по правилам ведения кассовых операций необходимо оформлять приходные кассовые ордера (ПКО) и расходные кассовые ордера (РКО) на основании чеков ККМ. Все данные о чеках, можно взять на сайте оператора фискальных данных (ОФД). Эта обработка сделает за вас в 1С - ПКО и РКО, Операции по платежным картам или Отчет о розничных продажах (может создать номенклатуру в 1С, указать налоги и др. реквизиты в документах в зависимости от налогообложения ККМ в торговой точке). Проверено на: OFD.RU / Первый ОФД / Такском / Платформа ОФД / Ярус / ОФД Яндекс / ОФД Астрал /ОФД СБИС / Гарант ОФД / КОРУС ОФД / КОНТУР ОФД / ОФД АО Тандер / ИнитПро / Группа Элемент/

3600 руб.

09.08.2017    148203    868    372    

527

Обработка 1С для печати чеков на кассе ККТ АТОЛ.ОНЛАЙН

ККМ Платформа 1С v8.3 1С:Комплексная автоматизация 1.х 1С:Бухгалтерия 2.0 1С:Управление торговлей 10 1С:Розница 2 1С:Управление нашей фирмой 1.6 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Россия Платные (руб)

Печать чеков по документам 1С РеализацияТоваров (РасходнаяНакладная), КорректировкаРеализации, СчетНаОплату, ЗаказКлиента, ЧекККМ, ПоступлениеНаРС. Соответствует требованиям 54-ФЗ. Одна облачная касса может использоваться всеми подразделениями организации, без привязки к рабочим местам. Электронные чеки отправляются на email клиента и всегда доступны в 1С, по требованию можно распечатать. Легкая настройка: после регистрации кассы на сайте АТОЛ.ОНЛАЙН, в обработке необходимо указать логин, пароль и идентификатор группы ККТ (берутся в личном кабинете АТОЛ.ОНЛАЙН). Одну кассу можно использовать с 1С при расчетах с физ. и юр. лицами и для интернет-магазина. HTTPS протокол интеграции API v4 / ФФД 1.05 или API v5 / ФФД 1.2.

21600 руб.

23.08.2022    10739    27    4    

24

Управление ККМ Атол и Штрих нового поколения (он-лайн ККТ под 54-ФЗ) с помощью текстового ini.файла для 1с77, 1с8Х любых конфигураций

Кассовые операции ККМ Платформа 1С v7.7 Платформа 1С v8.3 Конфигурации 1cv8 Конфигурации 1cv7 Россия Бухгалтерский учет Управленческий учет Платные (руб)

Программа для управления ККМ Атол и Штрих нового поколения (он-лайн ККТ под 54-ФЗ) с помощью текстового файла (ini файла) с изменениями  включена 1 лицензия  Для любых программ, которые умеют работать с текстовыми файлами. Внутри комплекта есть готовые к использованию обработки

4800 руб.

31.07.2017    165399    565    604    

197
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. пользователь 04.06.18 08:13
Сообщение было скрыто модератором.
...
2. Goruch 7 07.06.18 13:27 Сейчас в теме
Я правильно понимаю, что вы сверяете данные полученные и кассовой pos системы с данными в товароучетной системе?
Т.к. я не нашел никакого упоминание о том, как вытащить данные по z-отчету напрямую из кассы.
3. dima_home 239 08.06.18 10:46 Сейчас в теме
Мы сверяем данные о продажах и поступлении денежных средств, отраженные в учетной системе-1С с реальными чеками, пробитыми в ККМ, посредством ручного переноса контрольных сведений(дублирование) с чека ККМ "Z-ОТЧЕТ" в документ 1С "z-отчет" и их дальнейшее автоматическое сравнение.

Когда ККМ много, как у нас, бухгалтеру слишком сложно переносить с печатного чека ККМ "Z-ОТЧЕТ" сведения (ВЫРУЧКА,НОМЕРСМЕНЫ,ВОЗВРАТ_ПРИХОДА,ГРОСС_ИТОГ,НОМЕР_СМЕНЫ) в 1С, и тогда можно автоматизировать процесс получения данных Z-ОТЧЕТА напрямую из ККМ или из POS.

Сегодня можно уйти с пути получения контрольных сведений из ККМ в сторону получения контрольных сведений непосредственно из ОФД. Правда пока операторы ОФД не предоставляют API, но всегда есть выгрузки CSV за период.
4. dima_home 239 08.06.18 10:52 Сейчас в теме
Еще об автоматизации получения данных по z-отчету.
Драйвер ККМ АТОЛ при передачи задания на закрытие смены в кассу, возвращает все сведения, напечатанные в чеке Z-Отчет в POS систему. В свою очередь, POS системы АТОЛ при закрытии смены пишут в лог файл report лишь часть данных о z-отчете.

Поскольку мы для своей сети магазинов писали свою POS систему с нуля, то брали полные данные непосредственно из драйвера ККМ и передавали их в 1С уже сами через XML.
5. Bosma 69 08.06.18 12:09 Сейчас в теме
Интересная публикация. Смежный вопрос: Если используется в качестве POS системы АТОЛ, и соответственно смену в ККМ закрывает именно эта система, можно ли из другой внешней программы (пусть та же 1С) через драйвер ККМ получить данные напечатанные в Z-Отчете? У Вас, насколько я понял, совя POS система именно в момент закрытия смены ККМ получает ответ о Z-Отчете и складывает его в xml. Вопрос в том, что можно ли получить данные Z-Отчета из ККМ уже после закрытия смены.
7. dima_home 239 08.06.18 14:57 Сейчас в теме
К сожаление дважды войти в реку нельзя... то есть, либо вы закрываете смену в POS системе АТОЛ и она понимает это событие и соответственно закрывает у себя смену, либо вы сами пишете всю POS систему и делает что хотите.


Что касается прямого обращения к ККМ, можешьтут посмотреть ... даже есть примеры на C++. Можно например не закрывать смену, а попробовать получить с сведения по последней операции.


PS:/Отдельно: "ГРОСС ИТОГ".
Из POS АТОЛА можно получать строку с кодом 63... я писал в 3 ЭТАПЕ... но тогда придётся отказаться от контроля накопления (ГРОСС ИТОГА).
Как рассказывали тех.инженеры компании АТОЛ, когда мы разбирались, почему иногда ККМ не верно считает ГРОСС ИТОГ в новых ККМ, они сказали что ГРОСС ИТОГ не ведется в ФН (который подписывает чеки перед передачей в ОФД), он даже не хранит его, как это было раньше в ЭКЛЗ. Хранение и расчет ГРОСС ИТОГА сегодня возложен на сам ККМ, а она иногда, пробивая чеки не достоверно понимает статус(результат) пробития чеков. Это, кстати, та-же причина расхождения данных ККМ и 1С, когда ККМ (прямо подсоединенный к 1С) возвращает код ошибки при пробитии чека (например бумага закончилась), 1С считает что чек не пробит, а заходишь в ОФД, чек уже пробит.
6. Goruch 7 08.06.18 14:55 Сейчас в теме
Вы сказали:

Поскольку мы для своей сети магазинов писали свою POS систему с нуля, то брали полные данные непосредственно из драйвера ККМ и передавали их в 1С уже сами через XML.

Скажите, подкскажите каким образом вы получали данные о z-отчетах с ККМ?
Это какой-то обмен/запрос с ФР? Если да то подскажите где по -этому поводу почитать.
8. Denger 13.06.18 08:03 Сейчас в теме
(6)http://partner.atol.ru/files/dc/590/Drivers8_Um.pdf

ККМ хранит данные в регистрах. Посмотреть можно в прикрепленном скриншоте

Например, //ВНЕСЕНИЯ
driver.CheckType=1;
	driver.RegisterNumber=4;
	driver.GetRegister();
	ВНЕСЕНИЙ=Формат(driver.Summ,"Ч4.2");
	//ВЫПЛАТЫ
	driver.RegisterNumber=5;
	driver.GetRegister();
	ВЫПЛАТ=Формат(driver.Summ,"Ч4.2");
	
	
	Инкассация=ВозвратПараметра(10,0,0);
	Выручка=ВозвратПараметра(11,0,0);
	
	//КОЛ ПРОДАЖ
	driver.RegisterNumber=6;
	driver.CheckType=1;
	driver.GetRegister();
	КолПродаж=Формат(driver.count,"Ч(0)4");
	//КОЛ ВОЗВР
	driver.RegisterNumber=6;
	driver.CheckType=2;
	driver.GetRegister();
	КолВозв=Формат(driver.count,"Ч(0)4");
	
	//НОМЕР ККМ	
	driver.RegisterNumber=22;
	driver.GetRegister();
	НОМККМ=driver.SerialNumber;
	
	//НОМЕР СМЕНЫ, ДАТА
	driver.RegisterNumber=17;
	driver.GetRegister();
	НОМСМЕНЫ=driver.session;
	г=driver.Year;
	м=driver.Month;
	д=driver.Day;
	ДАТАСМЕНЫ=Дата(г,м,д);
Показать
Прикрепленные файлы:
9. dima_home 239 14.06.18 09:13 Сейчас в теме
гросс итог можно получить
driver.RegisterNumber=14;
//14 - Необнуляемая сумма после последней перерегистрации + сменный итог текущей смены (Summ)
driver.OperationType=0;
//0 – продажа;1 – покупка;2 – возврат продажи; 3 – возврат покупки.
driver.GetRegister();
НеобнуляемаяСумма=Формат(driver.count,"Ч(0)4");


Я вам советую направить силы не по съему данных с ККМ, а по съему данных с ОФД.

Хотя и в этом направлении еще много препятствий. Например наше ОФД - "Платформа О-Ф-Д" совсем сдурела - за возможность получить данные о ККМ требует оплату по 300 рублей в месяц за каждую ККМ. У нас более 400 касс это получается более 120'000 рублей в месяц. Легче посадить бухгалтера, который будет выгружать CSV за месяц, и его уже сверять в 1С внешней обработкой. Чтоб они от жадности лопнули ;)
12. dima_home 239 02.11.18 10:46 Сейчас в теме
Из практики
(9)
Например наше ОФД - "Платформа О-Ф-Д" совсем сдурела

Принято решение переходить на ОФД ТАКСКОМ... у них АПИ бесплатное (для нас по крайней мере)
10. Goruch 7 14.06.18 13:07 Сейчас в теме
У нас Контур. У него все хорошо и красиво, но нет API для того чтобы считать данные из ОФД в автоматизированном режиме...
Вот по-этому думаю как данные автоматизированно получать....
Плюс на данных из ОФД нет номера чека. Есть номер ФД и номер чека за смену, а это не та номера...
11. popenko 31.10.18 12:02 Сейчас в теме
понравился ваш подход. но есть вопрос, чисто практический - У вас много касс, а как работается бухгалтеру с формой списка документа (z-отчеты), может надо закладки хотя бы по подразделениям типа infostart.ru https://infostart.ru/public/16536/ или это лишнее? Я задал вопрос со стороны бухгалтера - если надо что -то посмотреть (найти, сравнить, да мало ли еще чего).
И еще не заметил.... может для подстраховки организовать хранилище с файлами из пос-системы
справочник -ХранилищеВнешнихФайлов
реквизиты - объект - документ ZОтчетФискальный
и Файл с типом ХранилищеЗначения
что вы на это скажите, исходя из большого кол-ва касс это надо или нет?
Прикрепленные файлы:
13. dima_home 239 02.11.18 11:33 Сейчас в теме
Напишите ваше сообщение
(11)
Журнал нужен лишь во время разбора полетов. С ним как правило работает только ревизор.
Он делает отбор по кассе и смотрит все z-отчеты кассы в хронологии.
Единственное в журнале есть колонка "Начальные сведения" - это булево является "красным" флагом для проверки - означает что бухгалтер начал подсчет ГРОСИТОГа или НОМЕРА СМЕНЫ с начало, без сверки с предыдущим z-отчетом.
Снимок1

За всеми кассами следит один бухгалтер-ревизор запуская единую проверку (сразу по всем ККМ), которая все и проверяет (пишу статью по этой единой проверке...).
Снимок2

А сам момент загрузки с касс, например от торговых представителей выглядит так:
Бухгалтер филиалов когда принимает от представителя выручку... может сразу увидеть все продажи, все чеки и все z-отчеты торгового представителя за всю смену его работы.
Снимок3
А потом нажав кнопочку выделить все, и нажав кнопки создать документы... загружает их в базу.

Для POS систем нет интерфейсов - из магазинов все грузится автоматом, без участия человека.
Прикрепленные файлы:
14. Новичок1с 4 19.07.21 09:31 Сейчас в теме
Доброго утра.

Подскажите пожалуйста, поможет ли нам этот документ, если у нас такая схема:
на основании док. реализация или наряд-заказ создаётся документ чек.
Далее кассир проводит оплату с помощью ККМ.
При "Закрытие смены - Инкассация все документы Чек удаляются, есть только документы чек на оплату.

Благодарю Вас за ответ
16. dima_home 239 12.08.21 12:06 Сейчас в теме
(14)
Здравствуй Новичок1с.
Статья немного о другом. Если у вас много касс, то нужно построить систему контроля отраженной выручки в 1С и фактическим пробитием чеков ККМ.
Метод который вы должны избрать, это метод проверок идеальный именно для вашего бизнеса, я в статье описывал наш механизм удобный для нас.

Сегодня, с появлением возможности напрямую загружать сведения о выручке с ОФД, мы ушли от документов "z-отчеты" в сторону документа "Отчет о закрытии смены ОФД"

И отчеты по сверкам написаны уже по этому документу.
Прикрепленные файлы:
15. Новичок1с 4 19.07.21 14:09 Сейчас в теме
Также я хотела бы спросить.

Не понятно,
ЕДИНАЯ ПРОВЕРКА ОШИБОК». Добавляем раздел по проверке сразу всех Z-отчетов, внесенных в 1С за определенный период.

Если нету этой обработки, то нужно создать свою??
В неё добавлять Создаем процедуры по проверке документов
блог модуля "Кто хочет посмотреть код проверок"

?

И что должно быть в обработке, какие реквизиты???
О обработках по автоматической загрузке данных с ККМ
17. dima_home 239 12.08.21 12:07 Сейчас в теме
(15)
ЕДИНАЯ ПРОВЕРКА ОШИБОК - это наша обработка, когда-нибудь напишу об этом отдельную статью.
Оставьте свое сообщение