Обработка выполнена для слегка измененного релиза УТ 11.1.9.51. Загрузка квитанций Яндекс.Деньги с помощью электронной почты универсана (в части загрузки писем в табличную часть обработки работает и на БП 3.0, УНФ 1.х - везде для режима управляемых форм). Для создания в УТ 11.1 документов поступления денежных средств по сути важен только один реквизит для учета номера заказа на сайте - по нему идет привязка по оплате.
Дополнительно. Данная задача по автоматизации приема и учета платежей (фактически уже поступивших раз зарегистрированы платежной системой, но еще не проведенных по банковской выписке) хоть и является самостоятельной, но из нее вытекала другая: в момент проведения документов поступления безналичных ДС создавать задачу менеджеру по продажам (или по доставке) и постановке ее в очередь. В такой связке можно оценить степень автоматизации работы фирмы по обслуживанию потребностей клиента.
ВНИМАНИЕ ПОКУПАТЕЛЯМ:
1. E-mail задается в коде обработки. Просьба перед покупкой сообщить параметры почтового ящика (если Вы не программист 1С и покупаете для дальнейшей модификации. Будет принято совместное решение по сохранению настроек в пользовательском режиме для удобства работы, либо обработка будет выслана Вам с Вашими настройками.
2. Формат квитанций реестра оплат может меняться, поэтому нужно заранее уточнить в техподдержке и прислать образец.
3. Обработка НЕ предназначена для типовой конфигурации Управление торговлей 11.1.9 и требует правки конфигурации (указано где и что) в части создания документов поступления денежных средств. Данная работа проводится заказчиком самостоятельно (если Вы программист 1С) либо оплачивается отдельно.
Формат входной квитанции в письме имеет вид:
2000258290430; 1973; 24880.00
Номер транзакции; Идентификатор клиента (Номер заказа на сайте); Сумма платежа;
Более подробно формат квитанций от Яндекс.Денег приведен ниже, а также включен в макет обработки для тестирования. Привожу строчки из квитанции (специально сделаны ошибки и дубли для тестирования):
29.06.2015, 09:50, "Yandex.Money Payment Center" :
РЕЕСТР ПЛАТЕЖЕЙ В ООО "Рога и копыта". № 727
Дата платежей: 28.06.2015
Номер транзакции; Идентификатор клиента; Сумма платежа; Валюта платежа; Сумма за вычетом комиссии; Время
платежа; Номер кошелька плательщика; Краткое описание; Тип платежа;
2000258290777; 1871; 24880.00; RUB; 24009.20; 28.06.2015 17:06:19; 419991837201967; testfirma.ru; AC;
Учитывая то, что формат сообщений будет часто меняться и, кроме этого, на начальном этапе внедрения потребуется отладка необходимо в подобных случаях заранее подготовиться к отладке. С этой целью я ввел в обработку макет и опцию "off-line" отладки. Нужно просто скопировать в макет текст с квитанцией и включить опцию "Отладка", а в конце отладки провести "генеральную репетицию" приема с e-mail этой же инструкции. Результат в обоих случаях должен быть одинаковым.
Результат работы обработки следующий:
Ниже исходная тестовая информация по заказу клиента (номер заказа на сайте выведен в журнале документов) и конечные результаты работы (включая сообщения об ошибках загрузки - дублируются в журнал регистрации методом глобального контекста ЗаписьЖурналаРегистрации(), т.к. предполагается запуск регламентным заданием для анализа нештатных ситуаций):
Процедура СказатьПользователю(ТекстСообщ) // Если фоновый процесс предусмотреть только в техн. журнал СП = Новый СообщениеПользователю; СП.Текст = ТекстСообщ; СП.Сообщить(); // Журнал регистрации УстановитьПривилегированныйРежим(Истина); ЗаписьЖурналаРегистрации("ошибка в обоработке ЗагрузкаКвитанцийОтЯндексДенег", УровеньЖурналаРегистрации.Ошибка, , ""+ТекстСообщ, "вывод ошибки"); УстановитьПривилегированныйРежим(Ложь); КонецПроцедуры
Тестовый заказ клиента в УТ 11.1:
Ситуация после загрузки в табличную часть квитанций и, также после создания документов.
Общий вид работы.
Результат работы.
Данная задача по интерграции оказалась интересной и сложной по следующим пунктам:
1. Прием писем и их первоначальная обработка встроенными средствами платформы 1С 8.3.6 без использования стороннего почтового клиента с помощью объекта "ИнтернетПочта".
Здесь тоже все не так просто как кажется: начиная от зависания сеанса 1С во время чтения заголовков переполненного ящика и заканчивая настройкой профиля электронной почты для выяснения настроек портов и протоколов (SSL). В частности для корректного доступа на pop.rambler.ru нужно включить опцию разрешения доступа сторонним почтовым клиентом, иначе будете получать непонятное сообщение в переводе с английского "некоректный логин или пароль". Также нужно учесть глючность методов ограничения и удаления писемПочта.ПолучитьЗаголовки(СтруктураОтбора):
СтрОтбора = Новый Структура; //СтрОтбора.Вставить("ПослеДатыОтправления", Дата(2015, 07, 01) ); //СтрОтбора.Вставить("Прочитанные", Ложь); //СтрОтбора.Вставить("Новые", Ложь); Заголовки=Почта.ПолучитьЗаголовки(СтрОтбора); Если Заголовки.Количество()=0 Тогда Возврат 0; //Предупреждение("В почтовом ящике нет входящих сообщений!", ,"Нет сообщений"); КонецЕсли; // Порядок чтения, пометка и удаление с сервера в ТЗ не оговорены! Логично пока не удалять с сервера, но помечать как прочитанные. Читать только непрочненные. Сообщения = Почта.Выбрать(Ложь, Заголовки, Истина); // Не удалять с сервера, но помечать как прочитанные.
2. Обработка полученного письма в формате HTML (иначе парсинг веб-страницы).
Это самый сложный пункт, поэтому кто сталкивался с подобными задачами большая просьба поделиться опытом и рассказать о подводных камнях парсинга.
Здесь столкнулся с проблемой что автоматически выделить текст "как есть" на сервере хотя бы с переносами строк очень непростая задача. На клиенте можно использовать Поле HTML-документа, но перерыв весь интернет нашел решение в DOM-технологии для получения из исходного HTML-документа сплошной строки текста без переноса (метод 1С 8.3 Новый ИнтернетПочта):
Для каждого ТекстСообщения Из Сообщение.Тексты Цикл Если ТекстСообщения.ТипТекста=ТипТекстаПочтовогоСообщения.HTML Тогда Попытка //Проеобразуем HTML в сплошную строку //штатными средствами 1С 8.3 без переносов: Построитель = Новый ПостроительDOM; ЧтениеHTML = Новый ЧтениеHTML; ЧтениеHTML.УстановитьСтроку(ТекстСообщения.Текст, ТекстСообщения.Кодировка); // Utf-8 по умолчанию. ДокументHTML = Построитель.Прочитать(ЧтениеHTML); ТекстВходящие = ТекстВходящие + ДокументHTML.Тело.ТекстовоеСодержимое+ВК_ПС; Исключение ПодробныйАнализОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке() ); СказатьПользователю("Ошибка при чтении-записи информации из письма "+ПодробныйАнализОшибки); Продолжить; КонецПопытки; ИначеЕсли ТекстСообщения.ТипТекста=ТипТекстаПочтовогоСообщения.ПростойТекст Тогда ТекстВходящие = ТекстВходящие+ТекстСообщения.Текст; Иначе СказатьПользователю("Поддерживаются только письма в HTML или простом текстовом формате (не размеченные)"); Продолжить; КонецЕсли; КонецЦикла; // Для каждого ТекстСообщения Из Сообщение.Тексты...
В результате получим результат в виде строки без переносов. Самое веселое, что придуманый способ отладки уже основывался на алгоритме перебора строк объекта ТекстовыйДокумент.
Как альтернатива можно попытаться удалить символы тегов из HTML вроде такого метода:
//Удаление html тегов из строки //Код 1C v 8.х RegExp = Новый COMОбъект("VBScript.RegExp"); RegExp.IgnoreCase = Ложь; //Игнорировать регистр RegExp.Global = Истина; //Поиск всех вхождений шаблона RegExp.MultiLine = Ложь; //Многострочный режим RegExp.Pattern = "]*>"; //Ищем теги HTML стр=RegExp.Replace(стр, ""); //Заменяем все теги на пустоту
Еще был вариант использовать COMОбъект("htmlfile"), но тут уже задача сильно усложнается в сторону знаний веб-дизайна.
HTML = Новый COMОбъект("htmlfile"); HTML.Open("text/html"); HTML.Write(ТекстПисьма); HTMLDocument = HTML.documentElement.document; Сообщить(HTMLDocument.Body.ChildNodes.length); Сообщить(HTMLDocument.getElementsByTagName("Table").length);
И третий вариант:
// Вариант обработки HTML-документа средствами 1С 8 ХТМЛТекст = ТекстПисьма.ПолучитьТекст(); НовыйHTMLДокумент = Новый COMОбъект("HtmlFile"); НовыйHTMLДокумент.open("text/html"); НовыйHTMLДокумент.write(ХТМЛТекст); НовыйHTMLДокумент.close(); ТегТела = НовыйHTMLДокумент.all.tags("BODY"); Для а = 0 По ТегТела.length - 1 Цикл ТегТела.item(а).innerHTML =" |
|
|
|<P></P>" + ТегТела.item(а).innerHTML; КонецЦикла; ТекстСообщенияДляОтправки = ""; Для а = 0 По НовыйHTMLДокумент.all.length - 1 Цикл Если НовыйHTMLДокумент.all.item(а).tagName = "HTML" Тогда ТекстСообщенияДляОтправки = НовыйHTMLДокумент.all.item(а).innerHTML; КонецЕсли; КонецЦикла;
Думаю так, что универсальный парсинг HTML-документа (в т.ч. и сторонними средствами) нужен тогда, когда структура документа заранее неизвестна и будет часто меняться. Здесь же структура относительно постоянно. Я привязался для разбивке строк к двум символам "двоеточие" в дате письма (13.11.2015 14:32:19), а также к 13-ти значному номеру транзакции в Яндекс.Деньги (и еще к 15-ти значному яндекс-кошельку). Метод чтения примитивный, но действенный:
Функция ЕстьТранзакцияВСтроке(СтрТекста, СтрТранзакция) Пока Истина Цикл Поз = Найти(СтрТекста, ";"); Если Поз=0 Тогда Возврат Ложь; КонецЕсли; ЯндексКошелек = ОставитьВСтрокеТолькоЦифры(Сред(СтрТекста, Поз-15, 15)); Если СтрДлина(ЯндексКошелек)=15 Тогда СтрТекста = Сред(СтрТекста, Поз+1); Продолжить; КонецЕсли; СтрТранзакция = ОставитьВСтрокеТолькоЦифры(Сред(СтрТекста, Поз-13, 13)); Если СтрДлина(СтрТранзакция)=13 Тогда Возврат Истина; // Это кошелек КонецЕсли; СтрТекста = Сред(СтрТекста, Поз+1); КонецЦикла; КонецФункции
3. Создание документов поступления денежных средств на основании заказа клиента.
Здесь задача обычная (хотя вся задача относится к разряду интеграции). Пока не стал самовольничать и вносить в конфигурацию новый реквизит - флаг загрузки обработкой (который нужно скрыть от пользователя и заполнять только этой обработкой программно). Также сама УТ 11.1.9 делает контроль взииморасчетов по заказу и не дает переплатить. В текущей версии оставил как есть. Даже в такой реализации двойной загрузке по оплате от клиента (переплаты) не будет, хотя тут нужно уточнять дополнительно по условиям оплаты:
Процедура СоздатьДокументы() Экспорт // Вопрос по ТЗ: Может создать в пользовательском режиме доп. реквизит (ЗагруженИзЯндексДенег и контроль этой обработкой? // Иначе только стандартный контроль взаиморасчетов по расшифровкам платежа настройками УТ 11.1.9 как сейчас чтоб заказ не был оплачен дважды УстановитьПривилегированныйРежим(Истина); Запрос = Новый Запрос; Запрос.УстановитьПараметр("ВхТЗ", Квитанции.Выгрузить(, "Загрузить, Загружен, НомерЗаказа") ); Запрос.Текст = "ВЫБРАТЬ | Вх.Загрузить, | Вх.Загружен, | Вх.НомерЗаказа КАК НомерЗаказа |ПОМЕСТИТЬ ВТ |ИЗ | &ВхТЗ КАК Вх | |ИНДЕКСИРОВАТЬ ПО | НомерЗаказа |; | |//////////////////////////////////////////////////////////////////////////////// |ВЫБРАТЬ | Заказ.Ссылка КАК Заказ, | Заказ.Дата КАК ДатаЗаказа, | ВТ.НомерЗаказа КАК НомерЗаказаССайта |ИЗ | Документ.ЗаказКлиента КАК Заказ | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ КАК ВТ | ПО Заказ.НомерЗаказаНаСайте = ВТ.НомерЗаказа |ГДЕ | Заказ.Проведен | И ВТ.Загрузить | И НЕ ВТ.Загружен | |УПОРЯДОЧИТЬ ПО | ДатаЗаказа"; РезультатЗапроса = Запрос.Выполнить(); Если РезультатЗапроса.Пустой() Тогда Возврат; КонецЕсли; Выборка = РезультатЗапроса.Выбрать(); Пока Выборка.Следующий() Цикл ДокЗаказ = Выборка.Заказ; Док = Документы.ПоступлениеБезналичныхДенежныхСредств.СоздатьДокумент(); Попытка Док.Заполнить(ДокЗаказ); Если Док.РасшифровкаПлатежа[0].СуммаВзаиморасчетов = 0 Тогда Продолжить; // Защита от двойной загрузки оплаты. Оплата по-условию только по одному заказу. КонецЕсли; Док.Дата = ТекущаяДата(); Док.НомерВходящегоДокумента = Выборка.НомерЗаказаССайта; //!!! Тип строка в Поступление ДС, а тут - тип число! Док.ДатаВходящегоДокумента = Док.Дата; // Уточнить. Может брать из квитанции по реестру как и номер входящего документа. Док.Комментарий = "# Создан обработкой загрузки квитанций от Яндекс.Денег по заказу с сайта "+Выборка.НомерЗаказаССайта; Док.Записать(РежимЗаписиДокумента.Проведение, РежимПроведенияДокумента.Неоперативный); // Уточнить про выписку банка. Квитанции.Найти(Выборка.НомерЗаказаССайта, "НомерЗаказа").Загружен = Истина; // Вопрос про контроль двойной оплаты (будет ли проводиться Поступление ДДС на основании заказа (расшифровка платежа) ?!? Исключение ПодробныйАнализОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке() ); СказатьПользователю("Ошибка при записи и проведении "+Док+" на основании "+ДокЗаказ+" Номер заказа с сайта <<"+ Выборка.НомерЗаказаССайта+">>"+ПодробныйАнализОшибки); КонецПопытки; КонецЦикла; УстановитьПривилегированныйРежим(Ложь); КонецПроцедуры
4. Встроенный отладчик для техподдержки.
Естественно, ничего не заменит тестирования в реальной ситуации, но, возможно, будет так, что работа с почтовым ящиком будет затруднительна (вдруг будут опции удаления писем). Для этого введена опция отладки загрузки. Справка включена в обработку (F1 в помощь).
Если изменился формат или выскакивает ошибка то для отладки проделать следующее:
4.1 На время работ вывести на форму флаг "Отладка" реквизит булево внешней обработки.
4.2 Скопировать текст письма с проблемной квитанцией с почтового ящика как есть.
4.3 Поместить в текстовый макет внешней обработки и сохранить.
4.4 В режиме предприятия под отладчиком установить флаг "Отладка".
Данная обработка с заранее заложенными возможностями отладки "off-line" скопировать текст письма из внешней почтовой программы с реестром платежей в макет обработки как обычный текст письма (без тегов HTML). Результат заполнения табличной части в обоих случаях должен быть одинаковым, т.к. используются общие механизмы.
P.S. Надеюсь, данная методика работы с квитанциями Yandex.Money для планирования входящих платежей от клиентов будет полезна. Жду от Вас замечаний и предложений по данной тематике.