Новшества по 54-ФЗ в области новой ККТ и все новые аббревиатуры из двух и трех букв (ОФД, ФН, ФД и т.д.) – одни из главных событий в торговой отрасли 2016-2017-2018 гг. Несмотря на всю сложность выполнения новых обязательных требований для магазинов, для рядовых пользователей появляется возможность автоматизировать получение данных о своих покупках от Операторов фискальных данных (ОФД).
Государство ввело QR-код в чеке как инструмент гражданского контроля. Можно скачать бесплатное мобильное приложение «Проверка кассового чека в ФНС России», отсканировать QR-код и проверить чек на корректность. Однако, практической пользы для накопления данных о своих покупках с последующим их анализом, мобильное приложение ФНС пока предоставляет в очень ограниченном объеме. Кроме того, остается вопрос сохранения относительной приватности покупателя, так как для получения возможностей сохранения чеков в своем личном кабинете необходимо зарегистрироваться с предоставлением своих персональных данных.
Вашему вниманию предлагается несколько вариантов использования данных со своих онлайн-чеков (на примере получения данных о покупках в магазинах «Лента»):
- внешняя обработка для получения данных о покупках по ФПД (фискальному признаку документа) и сумме чека. Теоретические обработка должна работать в любой конфигурации на управляемых формах, у которой режим совместимости позволяет работать с методами типа «СтрНайти». Открывается через меню «Файл»
- мобильное приложение на платформе 1С с возможностью сканирования QR-кодов и загрузки данных в мобильное приложение с последующим анализом на количество и сумму покупок по товарам. Мобильное приложение скомпилировано для ОС Android (хотя приложение проверялась на разных версиях системы Android 3-4-5-6, однако, возможна ситуация, когда приложение не будет работать). Разработанное мобильное приложение никуда не передает данные и не обменивается с другими базами данных, приложениями или программами. Для загрузки онлайн-чеков не используются какие-либо персональные данные пользователя. Все накопленные данные являются исключительно собственностью пользователя мобильного приложения. Поэтому вся ответственность за сохранностью и целостностью данных лежит исключительно на пользователе мобильного приложения. Если у вас не получается загрузить мобильное приложением, то попробуйте его скачать с облака ТПУ по ссылке: https://filecloud.tpu.ru/index.php/s/ejfo64JndsC78HV
- инструкция по работе с мобильным приложением. Инструкцию по работе с мобильным приложением можно также скачать по ссылке: https://filecloud.tpu.ru/index.php/s/sBQ9JmHxLYMKp3p
Ниже приведены исходные модули внешней обработки. Настоящая статья написана в поддержку доклада «Народный big data или 54-ФЗ на службе анализа и планирования для рядовых покупателей» на конференции INFOSTART EVENT 2017 COMMUNITY (прямая ссылка на доклад: http://event.infostart.ru/2017/agenda/#item644121) Если доклад пройдет в итоговый список выступлений, то будет также выложены исходные модули мобильного приложения.
Модули формы внешней обработки:
&НаСервере
Процедура ЗагрузитьЧекНаСервере()
ТекОбъект = РеквизитФормыВЗначение("Объект");
URL = СокрЛП(Объект.URLЧека);
ОтправляемаяКомандаНаФокус = URL;
URLРазделенный = ТекОбъект.РазделитьURL(URL);
Таймаут = 5;
ИмяСервера = URLРазделенный.ИмяСервера;
ПутьКФайлуНаСервере = URLРазделенный.ПутьКФайлуНаСервере;
Протокол = URLРазделенный.Протокол;
Порт = Неопределено;
ЗащищенноеСоединение = Неопределено;
Если Протокол = "https" Тогда
ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL;
КонецЕсли;
ПолнаяСтруктураURL = ТекОбъект.СтруктураURI(URL);
Если Не ПустаяСтрока(ПолнаяСтруктураURL.Порт) Тогда
ИмяСервера = ПолнаяСтруктураURL.Хост;
Порт = ПолнаяСтруктураURL.Порт;
КонецЕсли;
Прокси = ТекОбъект.ПолучитьПрокси(Протокол);
Попытка
Соединение = Новый HTTPСоединение(ИмяСервера, Порт, , , Прокси, Таймаут, ЗащищенноеСоединение);
Исключение
ИнформацияОбОшибке = ИнформацияОбОшибке();
СообщениеОбОшибке = НСтр("ru = 'Ошибка при создании HTTP-соединения с сервером %1:'") + Символы.ПС + "%2";
ВызватьИсключение СообщениеОбОшибке;
КонецПопытки;
Заголовки = Новый Соответствие;
HTTPЗапрос = Новый HTTPЗапрос(ПутьКФайлуНаСервере, Заголовки);
HTTPОтвет = Соединение.Получить(HTTPЗапрос);
ФайлОтвета = HTTPОтвет.ПолучитьТелоКакСтроку();
HTTPОтвет = ТекОбъект.СтроковыеФункцииКлиентСерверИзвлечьТекстИзHTML(ФайлОтвета);
КоличествоТоваровВЧеке = СтрЧислоВхождений(HTTPОтвет,"vmb_i67bc30956372029315_vblock")/13 - 1;
Для НомерТовара = 0 По КоличествоТоваровВЧеке Цикл
ПоправкаНаДлинуНомераСтроки = 0;
Если НомерТовара >= 10 Тогда
ПоправкаНаДлинуНомераСтроки = 1;
КонецЕсли;
ТекНачалоСтрокиТовара = СтрНайти(HTTPОтвет,"vmb_i67bc30956372029315_vblock"+СокрЛП(НомерТовара),,,2);
Если ТекНачалоСтрокиТовара = 0 Тогда
Продолжить;
КонецЕсли;
НачалоСтрокиТовара = ТекНачалоСтрокиТовара + 54 + ПоправкаНаДлинуНомераСтроки;
ОкончаниеСтрокиТовара = СтрНайти(HTTPОтвет,"</span>",,НачалоСтрокиТовара);
ДлинаНазванияТовара = ОкончаниеСтрокиТовара - НачалоСтрокиТовара;
НазваниеТовара = Сред(HTTPОтвет,НачалоСтрокиТовара,ДлинаНазванияТовара);
//количество
НачалоСтрокиКоличества = СтрНайти(HTTPОтвет,"vmb_i67bc30956372029315_vblock"+СокрЛП(НомерТовара),,,3) + 54 + ПоправкаНаДлинуНомераСтроки;
ОкончаниеСтрокиКоличества = СтрНайти(HTTPОтвет,"</span>",,НачалоСтрокиКоличества);
ДлинаКоличества = ОкончаниеСтрокиКоличества - НачалоСтрокиКоличества;
Количество = Сред(HTTPОтвет,НачалоСтрокиКоличества,ДлинаКоличества);
//цена
НачалоСтрокиЦены = СтрНайти(HTTPОтвет,"vmb_i67bc30956372029315_vblock"+СокрЛП(НомерТовара),,,4) + 54 + ПоправкаНаДлинуНомераСтроки;
ОкончаниеСтрокиЦены = СтрНайти(HTTPОтвет,"</span>",,НачалоСтрокиЦены);
ДлинаЦены = ОкончаниеСтрокиЦены - НачалоСтрокиЦены;
Цена = Сред(HTTPОтвет,НачалоСтрокиЦены,ДлинаЦены);
//сумма
НачалоСтрокиСуммы = СтрНайти(HTTPОтвет,"vmb_i67bc30956372029315_vblock"+СокрЛП(НомерТовара),,,9) + 55 + ПоправкаНаДлинуНомераСтроки;
ОкончаниеСтрокиСуммы = СтрНайти(HTTPОтвет,"</span>",,НачалоСтрокиСуммы);
ДлинаСуммы = ОкончаниеСтрокиСуммы - НачалоСтрокиСуммы;
Сумма = Сред(HTTPОтвет,НачалоСтрокиСуммы,ДлинаСуммы);
НоваяСтрока = Объект.Покупки.Добавить();
НоваяСтрока.НазваниеТовара = НазваниеТовара;
НоваяСтрока.Количество = Количество;
НоваяСтрока.Цена = Цена;
НоваяСтрока.Сумма = Сумма;
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Процедура ЗагрузитьЧек(Команда)
Объект.Покупки.Очистить();
СразуСсылкаНаЧек = "http://receipt.taxcom.ru/v01/show?fp=" + СокрЛП(Объект.ФПД) + "&s=" + СокрЛП(Формат(Объект.СуммаПокупки,"ЧГ=0")) + "&sf=False&sfn=False";
Объект.URLЧека = СразуСсылкаНаЧек;
ЗагрузитьЧекНаСервере();
КонецПроцедуры
&НаКлиенте
Процедура ПерейтиПоСсылке(Команда)
ЗапуститьПриложение(Объект.URLЧека);
КонецПроцедуры
Модули объекта внешней обработки:
Функция РазделитьURL(URL) Экспорт
Результат = ПолучениеФайловИзИнтернетаКлиентСервер.РазделитьURL(URL);
Если Результат.Свойство("ПустьКФайлуНаСервере") Тогда
Результат.Вставить("ПутьКФайлуНаСервере", Результат.ПустьКФайлуНаСервере);
КонецЕсли;
Возврат Результат;
КонецФункции
Функция СтруктураURI(СтрокаURI) Экспорт
Возврат ОбщегоНазначенияКлиентСервер.СтруктураURI(СтрокаURI);
КонецФункции
Функция ПолучитьПрокси(Протокол) Экспорт
Попытка
Возврат ПолучениеФайловИзИнтернетаКлиентСервер.ПолучитьПрокси(Протокол);
Исключение
Возврат Неопределено;
КонецПопытки;
КонецФункции
Процедура УстановитьHTTPЗаголовки(Заголовки) Экспорт
Куки = Новый Соответствие;
Куки.Вставить("new-int-rel", "1");
Куки.Вставить("expires", Формат(ДобавитьМесяц(ТекущаяДата(), 1), "Л=en_US; ДФ='ddd, dd-MMM-yyyy H:mm:ss G""MT'"));
Куки.Вставить("path", "/");
СтрКуки = "";
Для Каждого Кука Из Куки Цикл
СтрКуки = СтрКуки + "; " + Кука.Ключ + "=" + КодироватьСтроку(Кука.Значение, СпособКодированияСтроки.КодировкаURL);
КонецЦикла;
СтрКуки = Сред(СтрКуки, 3);
Заголовки.Вставить("Cookie", СтрКуки);
КонецПроцедуры
Функция СтроковыеФункцииКлиентСерверИзвлечьТекстИзHTML(Знач ИсходныйТекст) Экспорт
Результат = "";
Текст = НРег(ИсходныйТекст);
Позиция = Найти(Текст, "<body");
Если Позиция > 0 Тогда
Текст = Сред(Текст, Позиция + 5);
ИсходныйТекст = Сред(ИсходныйТекст, Позиция + 5);
Позиция = Найти(Текст, ">");
Если Позиция > 0 Тогда
Текст = Сред(Текст, Позиция + 1);
ИсходныйТекст = Сред(ИсходныйТекст, Позиция + 1);
КонецЕсли;
КонецЕсли;
Позиция = Найти(Текст, "</body>");
Если Позиция > 0 Тогда
Текст = Лев(Текст, Позиция - 1);
ИсходныйТекст = Лев(ИсходныйТекст, Позиция - 1);
КонецЕсли;
ПозицияНачалаУдаления = стрНайти(Текст, "ttc_multiple_block_panel",,1);
ДлинаТекста = СтрДлина(Текст);
ВтораяЧастьТекста = Прав(Текст,ДлинаТекста - ПозицияНачалаУдаления - 29);
ИсходныйТекст = ВтораяЧастьТекста;
Результат = Результат + ИсходныйТекст;
Возврат СокрЛП(Результат);
КонецФункции
Данная статья не претендует на универсальность в загрузке данных чеков с ОФД. Автор хотел лишь поделиться своим мнением и некоторыми наработками в вопросе работы с доступными данными с сайтов ОФД.