/MercuryServer

http сервер для печати на Меркурии 119Ф usb по сети.

Primary LanguageC#MIT LicenseMIT

MercuryServer

Печать на Меркурий 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-запроса.

Сервер умеет обрабатывать следующие запросы:

  1. /openshift открытие смены

  2. /closeshift закрытие смены

  3. /status состояние фискального регистратора

  4. /printxreport печать х-отчета

  5. /printcheck печать чека

При печати чека проверяется состояние смены и если нужно открыть смену, то она открывается. Если нужно закрыть смену, то смена закрывается, открывается и печатается чек.

Результат возвращается в виде json, согласно документации. Если при выполнении запроса происходит ошибка, то в json возвращается поле "error" со строковым описанием ошибки.

openshift

Вызывается метод драйвера OpenShift2.

Тело запроса

{
   "CashierName": "имя кассира",
   "CashierVATIN": "инн кассир"
}

Тело ответа

{
    "SessionNumber": номер текущей смены,
    "DocumentNumber": номер отчета об открытии смены,
    "UrgentReplacementFN":  Признак необходимости срочной замены ФН,
    "MemoryOverflowFN":  Признак переполнения памяти ФН,
    "ResourcesExhaustionFN": Признак исчерпания ресурса ФН,
    "OFDtimeout": Признак того, что подтверждение оператора для переданного фискального документа отсутствует более двух дней. Для ФД с версией ФФД 1.0 более 5 дней
}

closeshift

Вызывается метод драйвера CloseShift2.

Тело запроса

{
   "CashierName": "имя кассира",
   "CashierVATIN": "инн кассир"
}

Тело ответа

{
    "SessionNumber": номер текущей смены,
    "DocumentNumber": номер отчета о закрытии смены,
    "NumberOfChecks": Количество кассовых чеков за смену,
    "NumberOfDocuments": Количество общее ФД за смену,
    "BacklogDocumentsCounter": Количество непереданных документов,
    "BacklogDocumentFirstNumber"  Номер первого непереданного документа,
    "BacklogDocumentFirstDateTime" Дата и время первого из непереданных документов,
    "UrgentReplacementFN":  Признак необходимости срочной замены ФН,
    "MemoryOverflowFN":  Признак переполнения памяти ФН,
    "ResourcesExhaustionFN": Признак исчерпания ресурса ФН,
    "OFDtimeout": Признак того, что подтверждение оператора для переданного фискального документа отсутствует более двух дней. Для ФД с версией ФФД 1.0 более 5 дней
}

status

Вызывается метод драйвера GetCurrentStatus.

Тело запроса

Пустое.

Тело ответа

{
    "CheckNumber": Номер последнего пробитого фискального документа из ФН,
    "SessionNumber": Номер смены,
    "SessionState":  Статус смены: 1-Закрыта, 2-Открыта,
    "BacklogDocumentsCounter": Количество непереданных документов,
    "BacklogDocumentFirstNumber"  Номер первого непереданного документа,
    "BacklogDocumentFirstDateTime" Дата и время первого из непереданных документов
}

printxreport

Вызывается метод драйвера PrintXReport.

Тело запроса

Пустое.

Тело ответа

Пустое.

printcheck

Вызывается метод драйвера ProcessCheck.

{
   "CashierName": "имя кассира",
   "CheckPackage": "xml с чеком"
}

Тело ответа

{
    "CheckNumber": Номер фискального чека, возвращаемый ФН,
    "SessionNumber": Номер открытой смены,
    "FiscalSign":  Фискальный признак,
    "AddressSiteInspections": Адрес сайта проверки
}

Лог сервера

В папке сервера формируется подробный лог запросов и ответов. Файл mercury.log. Настройки лога log4net.config.

Пример печати чека из 1С:Предприятия 8.3

Кусок кода, который печатает чек на сервере меркурия. Таймаут 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, ""));
	Возврат;
КонецЕсли;