Печать на Меркурий 119Ф usb по локальной сети. Для печати чеков с терминального сервера или произвольного компьютера в сети пришлось написать обертку над фирменным драйвером.
Данный проект представляет собой простейший однопоточный http-сервер, который транслирует post запросы в вызовы методов com-объекта.
Подключаем Меркурий-119Ф к компьютеру.
Устанавливаем драйвер usb https://www.incotexkkm.ru/attachments/54-fz/119f/Mercury_119F_USB.zip.
Устанавливаем драйвер "Инкотекс: ККТ Меркурий с передачей данных в ОФД (54-ФЗ)" (М119Ф, МФ) https://forum.incotexkkm.ru/viewtopic.php?f=19&t=2066 файл MercuryOfdFPDrv.exe.
Собираем проект, например, в визуал-студии комьюнити 2017. Или качаем собранный проект и разворачиваем http://philya.com/ms/MercuryServer_v1_1.zip
Вешаем в автозагрузку MercuryServer.exe.
В папке с MercuryServer.exe есть файл конфигурации MercuryServer.exe.config, в котором нужно настроить ip-адрес и порт ОФД. По умолчанию в качестве ОФД настроен Петер-сервис http://ofd.ru.
<add key="ofdIP" value="94.143.160.11"/>
<add key="ofdPort" value="4000"/>
Так же может понадобиться изменить порт http сервера Меркурия.
<add key="httpServerPort" value="8090" />
Запускаем MercuryServer.exe, в панели уведомлений появляется иконка сервера. Левый клик по иконке отображает окно сервера, в котором показывается текущее состояние Меркурия 119Ф. Правый клик по иконке позволяет закрыть сервер. Перед повторным запуском стоит выждать до 30 секунд, потому что драйвер меркурия может отправлять данные в ОФД и не успеть закрыться.
В браузере в строке адреса набираем localhost:8090 нажимаем ентер, смотрим на страницу ошибки сервера Меркурия.
При настройке печати по сети аналогично в браузере компьютера, с которого будут печататься чеки, набираем айпи-адрес-серверамеркурия:8090 и смотрим страницу ошибки. Если страницы ошибки нет, то проверяем настройки брендмауэра.
В папке драйвера Меркурия есть документация C:\Program Files (x86)\incotex\MercuryOfdFPDriver\MercuryComOFDFPDriver Manual.pdf Параметры методов драйвера оборачиваются в json и передаются как тело POST-запроса.
Сервер умеет обрабатывать следующие запросы:
-
/openshift открытие смены
-
/closeshift закрытие смены
-
/status состояние фискального регистратора
-
/printxreport печать х-отчета
-
/printcheck печать чека
При печати чека проверяется состояние смены и если нужно открыть смену, то она открывается. Если нужно закрыть смену, то смена закрывается, открывается и печатается чек.
Результат возвращается в виде json, согласно документации. Если при выполнении запроса происходит ошибка, то в json возвращается поле "error" со строковым описанием ошибки.
Вызывается метод драйвера OpenShift2.
Тело запроса
{
"CashierName": "имя кассира",
"CashierVATIN": "инн кассир"
}
Тело ответа
{
"SessionNumber": номер текущей смены,
"DocumentNumber": номер отчета об открытии смены,
"UrgentReplacementFN": Признак необходимости срочной замены ФН,
"MemoryOverflowFN": Признак переполнения памяти ФН,
"ResourcesExhaustionFN": Признак исчерпания ресурса ФН,
"OFDtimeout": Признак того, что подтверждение оператора для переданного фискального документа отсутствует более двух дней. Для ФД с версией ФФД 1.0 более 5 дней
}
Вызывается метод драйвера CloseShift2.
Тело запроса
{
"CashierName": "имя кассира",
"CashierVATIN": "инн кассир"
}
Тело ответа
{
"SessionNumber": номер текущей смены,
"DocumentNumber": номер отчета о закрытии смены,
"NumberOfChecks": Количество кассовых чеков за смену,
"NumberOfDocuments": Количество общее ФД за смену,
"BacklogDocumentsCounter": Количество непереданных документов,
"BacklogDocumentFirstNumber" Номер первого непереданного документа,
"BacklogDocumentFirstDateTime" Дата и время первого из непереданных документов,
"UrgentReplacementFN": Признак необходимости срочной замены ФН,
"MemoryOverflowFN": Признак переполнения памяти ФН,
"ResourcesExhaustionFN": Признак исчерпания ресурса ФН,
"OFDtimeout": Признак того, что подтверждение оператора для переданного фискального документа отсутствует более двух дней. Для ФД с версией ФФД 1.0 более 5 дней
}
Вызывается метод драйвера GetCurrentStatus.
Тело запроса
Пустое.
Тело ответа
{
"CheckNumber": Номер последнего пробитого фискального документа из ФН,
"SessionNumber": Номер смены,
"SessionState": Статус смены: 1-Закрыта, 2-Открыта,
"BacklogDocumentsCounter": Количество непереданных документов,
"BacklogDocumentFirstNumber" Номер первого непереданного документа,
"BacklogDocumentFirstDateTime" Дата и время первого из непереданных документов
}
Вызывается метод драйвера PrintXReport.
Тело запроса
Пустое.
Тело ответа
Пустое.
Вызывается метод драйвера ProcessCheck.
{
"CashierName": "имя кассира",
"CheckPackage": "xml с чеком"
}
Тело ответа
{
"CheckNumber": Номер фискального чека, возвращаемый ФН,
"SessionNumber": Номер открытой смены,
"FiscalSign": Фискальный признак,
"AddressSiteInspections": Адрес сайта проверки
}
В папке сервера формируется подробный лог запросов и ответов. Файл mercury.log. Настройки лога log4net.config.
Кусок кода, который печатает чек на сервере меркурия. Таймаут http соединения нужно ставить достаточно большим, потому что печать большого чека может занимать продолжительное время.
ДокЧек = "<?xml version=""1.0"" encoding=""UTF-8""?>
|<CheckPackage>
|<Parameters PaymentType=""1"" TaxVariant=""#Налогообложение#"" #ИННКассира#/>
|<Positions>
|#Строки#
|</Positions>
|<Payments Cash=""#СуммаЧека#""/>
|</CheckPackage>";
ДокЧек = СтрЗаменить(ДокЧек, "#Налогообложение#", 2); // 0-общая, 1-усн-доход, 2 - усн-расход, 3-енвд
ДокЧек = СтрЗаменить(ДокЧек, "#ИННКассира#", "CashierVATIN=""123456789012""");
ШаблонСтроки = "<FiscalString Name=""#Товар#"" Quantity=""#Количество#"" Price=""#Цена#"" Tax=""#СтавкаНДС#"" Amount=""#Сумма#""/>";
Строки = "";
Сумма = 0;
Для Каждого СтрТоваров Из СтрокиДокумента Цикл
ТекСтрока = ШаблонСтроки;
ТекСтрока = СтрЗаменить(ТекСтрока, "#Товар#", ЭкранироватьСимволы(СокрЛП(СтрТоваров.Номенклатура)));
ТекСтрока = СтрЗаменить(ТекСтрока, "#Количество#", Формат(СтрТоваров.Количество, "ЧРД=.; ЧГ=0"));
ТекСтрока = СтрЗаменить(ТекСтрока, "#Цена#", Формат(СтрТоваров.Цена, "ЧРД=.; ЧГ=0"));
ТекСтрока = СтрЗаменить(ТекСтрока, "#СтавкаНДС#", "none"); //СтавкаНДСМеркурий(СтрТоваров.СтавкаНДС, ПлательщикНДС));
ТекСтрока = СтрЗаменить(ТекСтрока, "#Сумма#", Формат(СтрТоваров.Сумма, "ЧРД=.; ЧГ=0"));
Строки = Строки + ТекСтрока;
Сумма = Сумма + СтрТоваров.Сумма;
КонецЦикла;
ДокЧек = СтрЗаменить(ДокЧек, "#Строки#", Строки);
ДокЧек = СтрЗаменить(ДокЧек, "#СуммаЧека#", Формат(Сумма, "ЧРД=.; ЧГ=0"));
ПараметрыЗапроса = Новый Структура();
ПараметрыЗапроса.Вставить("CashierName", "Иванов И.И.");
ПараметрыЗапроса.Вставить("CheckPackage", ДокЧек);
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, ПараметрыЗапроса);
ТелоЗапроса = ЗаписьJSON.Закрыть();
Запрос = Новый HTTPЗапрос("/printcheck");
Запрос.УстановитьТелоИзСтроки(ТелоЗапроса);
Соединение = Новый HTTPСоединение("айпи сервера меркурия", 8090,,,,60);
Попытка
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Исключение
ПоказатьПредупреждение(,"Не удалось пробить чек! Нет соединения с сервером чеков!");
Возврат;
КонецПопытки;
Если Ответ.КодСостояния <> 200 Тогда
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(Ответ.ПолучитьТелоКакСтроку());
Результат = ПрочитатьJSON(ЧтениеJSON, Ложь);
ПоказатьПредупреждение(,"Не удалось пробить чек! " + ?(Результат.Свойство("error"), Результат.error, ""));
Возврат;
КонецЕсли;