Форум OlegON > Программы и оборудование для автоматизации торговли > Системы автоматизации торговли > КИС Lack & УС Land

УС Лэнд:ЕГАИС – 2017. Обсуждение программы, предложения, замечания, вопросы : КИС Lack & УС Land

29.03.2024 10:30


09.03.2017 17:26
winmasta
 
Цитата:
AndreyZh Нужно проверить работу курла... причин может быть много... рецептов множество в "доставании" начиная со страницы: https://olegon.ru/showthread.php?t=23765&page=16 я бы для начала удалил все курлы с ПК и положил в каталог программы, тот который прилагал с дистрибутивами... сделать батник с курлом и проверить его работу
да, я уже успел проверить и сообщение отредактировал )))
09.03.2017 17:26
AndreyZh
 
Цитата:
winmasta обновил усегу, а файлы из старой папки (в т.ч. курл) не переписал, может сделать отдельную ошибку по курлу ?
и что? каждая версия в новой папке?
09.03.2017 17:29
winmasta
 
Цитата:
AndreyZh и что? каждая версия в новой папке?
да в этот раз как-то в спешке криво сделал
09.03.2017 17:34
AndreyZh
 
Цитата:
winmasta да в этот раз как-то в спешке криво сделал
1. Был же сделан автомат hle repair -> можно сделать батник, что всё, как надо обновлялось
2. С Вашего позволения перемещаюсь домой (20 км до гаража), ещё и воду от ворот откидывать... если нужен буду на форуме пришлите SMS, как доберусь до дома - "включусь"
10.03.2017 09:03
AndreyZh
 
Цитата:
winmasta Добрый день, ошибка при обработке входящих запросов, хотя в УТМ доки висят, подробности на скринах.
Продолжаю раскрывать исходный код (алгоритмы) для грамотных пользователей - нужно же знать, что кушаете?

Как отсылает запросы программа, например типичный запросик:
Код:
//  Запрашиваю конкретную накладную по извлеченной строке запроса

//  Составляю строку вызова cURL
cZ  := cgpCurl+[curl -X GET ]+cZap+[ > ]+cdData+"prih_tmp.xml"

//  Запускаю команду на выполнение. Мне неизвестно будет ли она выполнена
RUN (cZ)

/*
Даю паузу - полоска сверху с тестом и рекомендацией, что бы
УТМ обработал запрос, вернул файл и ОС его полностью сохранила
на диске.
*/
pInkey(ngWait)

/*
Анализ успешности создания файла ответа. Пытаюсь это 
проверять ngWait секунд. Возвращаю результат проверки
и в зависимости от него произвожу дальнейшие работы
*/
IF !lReplUTM(cdData+"prih_tmp.xml",ngWait) THEN LOOP
Сообщение выдаётся при неудачной попытке обнаружить файл, что может быть по огромному, в том числе неизвестным мне причинам. Код функции проверки ответа от УТМ

Код:
* ---------------------------------------------------------------------------
* 	Ожидание ответа УТМ - появление "семафора" == заранее стертого файла с
*	именем в течении переданного ххх числа секунд
FUNC lReplUTM(cFile,nSec)
	LOCA cOldCol:=Setcolor(), nTime:=0, lWait:=FALSE

	//	Просто сообщение с задержкой
	ftxt_act("   Ожидаю в течение "+Alltrim(Str(nSec))+" секунд получения квитанции (ответа) от УТМ",cHelpc)
	DO WHIL nTime < nSec
		X_DEMO
		IF File(cFile)
			IF FileSize(cFile) > 1
				lWait	:= TRUE
				EXIT
			ENDI
		ENDI
		Inkey(1)
		nTime++
	ENDD
	fDeact(cOldCol)
	IF !lWait
		Errmess("Не дождался ответа от УТМ - может быть у ЕГАИС (УТМ) какие-то проблемы? Пожалуйста проверьте работоспособность УТМ транспорта! "+;
                "Так же возможны причины такого ответа: Слишком малая пауза в настройке и УТМ не успевает обработать запрос. Исчез или используется другой "+;
                "или заблокирован антивирусом cUrl - возьмите из дистрибутива. Возможно был удален запрос или накладная в другой копии?",cError)
		RETU FALSE
	ENDI
	RETU TRUE
То есть в будущих версий реакция на ошибки будет такой:

11.03.2017 04:01
winmasta
 
Можно добавить проверку if exist curl.exe в path и если нет - конкретизировать ошибку.
11.03.2017 07:26
AndreyZh
 
Цитата:
winmasta Можно добавить проверку if exist curl.exe в path и если нет - конкретизировать ошибку.
Сделал! Однако отмечу, что всё не так "просто":

1. Кто-то захочет использовать другую версию cURL;
2. Или cURL можно кинуть в каталог Windows, или, как у меня прописать пути в настройке OS

Посему... сделал, как хотите, но данную возможность можно отключить в настройке программы. Кроме того не запрещаю работу, но запрашиваю дальнейшие действия. Нюансы видны в исходнике:

Код:
    //  Проверяю наличие cURL в каталоге по маршруту настройки и сличаю размер с прилагаемым мной образцом
    IF lgpCurl                      //  В настройке программы можно отключить данный параметр - проверку
        aArr    := Directory(cgpCurl+"curl.exe")
        IF Len(aArr) <= 0
            IF !Fyn("Программы cURL нет в директории по настройке. Продолжить?",cError) THEN RETU
        ELSE
            IF aArr[1,2] <> 2226688 //  Не совпадает с размером предлагаемым мной cURL - другая версия?
                IF !Fyn("Программа cURL имеет неверный размер. Возможно вирусы! Продолжить?",cError) THEN RETU
            ENDI
        ENDI
    ENDI
11.03.2017 14:59
winmasta
 
Подскажите, а что за код, синтаксис не гуглится, или кое-какие буквы убраны специально?
11.03.2017 17:50
AndreyZh
 
Цитата:
winmasta Подскажите, а что за код, синтаксис не гуглится, или кое-какие буквы убраны специально?
Система пишется на open source системе разработки xHarbour без использования GUI библиотек и собирается компилятором под Win 32. Этот код, при отсутствии у меня желания можно скомпилировать под любую OS, в частности Linux. Подробнее можно почитать: https://olegon.ru/showthread.php?t=17546. Привожу его иногда для понимания логики работы программы, т.к. действия подробно комментирую...
12.03.2017 08:29
AndreyZh
 
Приведу ещё пример исходного кода... Это работающие конструкции, проверенные на реальной кассе Атол 30Ф... Из него можно понять, что допилить с описанием "УСЕга" под пресловутый ФЗ - это дело пары недель... или может быть полезен изобретателям "лисапедов" для своих кассовых программ.

Тестовая программа интеграции с on-line кассой:
Код:
#include "..\LACK\LS\PRG\laks.ch"
MEMV oKkm

* ---------------------------------------------------------------------------
*   Головной модуль программы
PROC Main()
    LOCA nVal:=0, cVal:="", nSel:=1
    PRIV oKkm

    //  Глобальные системные установки пакета.
    SET DATE GERMAN
    SET DELE ON
    SET ESCA ON
    SET SCOR OFF
    SET WRAP ON
    SET CENT ON

    //  Стандартная цветовая гамма программы
    PRIV cMainc_c   := "GR+/B,N+/W,,,N/W",  cMainc_m    := "W/N,N/W,,,N/W+"
    PRIV cColor_c   := "N/W,GR+/B,,,N/G",   cColor_m    := "W/N,N/W,,,N/W+"
    PRIV cError_c   := "N/R+,W/N,,,W/B",    cError_m    := "W+/N,N/W,,,W/N"
    PRIV cHelpc_c   := "N/G,R/G,,,N/G+",    cHelpc_m    := "N/W,W/N,,,N/W+"
    PRIV cOther_c   := "N+/G,W/N,,,B/G",    cOther_m    := "N/W,W/N,,,N/W"
    PRIV cMainc     := IF(ISCOLOR(),cMainc_c,cMainc_m)
    PRIV cColor     := IF(ISCOLOR(),cColor_c,cColor_m)
    PRIV cError     := IF(ISCOLOR(),cError_c,cError_m)
    PRIV cHelpc     := IF(ISCOLOR(),cHelpc_c,cHelpc_m)
    PRIV cOther     := IF(ISCOLOR(),cOther_c,cOther_m)
    PRIV l_mus      := TRUE

    CLS
    
   
    //  Декларирование структуры с обработкой ошибок выполнения - недоступность драйвера ККМ
    TRY     
		oKkm    := CreateObject('AddIn.FprnM45')
    CATCH
        fErrQuit("Не могу открыть драйвер Атол! Возможно он не установлен на ПК",cError )
        RETU
    END

    //  Занимаем порт ККМ и проверяем его доступность - может быть занят мной или другими службами
    oKkm:DeviceEnabled  := TRUE
    IF oKkm:ResultCode <> 0     //  При возврате ошибки занимания порта 14 - Занят порт (в драйверах usb-ethernet занимает порт)
        ErrMess("Возвращен код ошибки при резервировании порта = "+Alltrim(Str(oKkm:ResultCode)),cError)
        RETU
    ENDI

    //  Получаем состояние ККМ - возврат кода ошибки или 0
    IF oKkm:GetStatus <> 0
        ErrMess("Возвращено неопределенное состояние ККМ. Код ошибки = "+Alltrim(Str(oKkm:GetStatus)),cError)
        RETU
    ENDI

    //***   Проверяем на всякий случай ККМ на фискализированность, что бы не испортить рабочую ККМ
    IF oKkm:Fiscal
        IF !Fyn("ККМ фискализирована! Вы действительно хотите продолжить?",cError) THEN RETU
    ENDI

    
    //***   Циклический вызов меню задач кассового аппарата - изолированные функции низкого уровня
    DO WHIL TRUE
        CLS
    
        //  Пополняемое меню задач для кассового аппарата
        @ 1,1 PROM "Открыть смену - выставляю глобальный флаг"
        @ 2,1 PROM "Проверить наличие открытых чеков- закрыть"
        @ 3,1 PROM "Входим в режим кассира. Пример для продаж"        
        @ 4,1 PROM "Прод. товаров с печатью чека-общий подход"
        @ 5,1 PROM "Внесение или выплата денег из кассы.Общий"
        @ 6,1 PROM "Резерв...                                "
        @ 7,1 PROM "Резерв...                                "
        @ 8,1 PROM "Резерв...                                "
        @ 9,1 PROM "Провер. наличие открытого чека. Закрываем"
        @10,1 PROM "В случае открытой смены печатаем z-отчет "
        @11,1 PROM "Печать Х-отчета. Не закрывается опердень!"
        @12,1 PROM "Закрыть смену    - убираю глобальный флаг"        
        MENU TO nSel
        IF nSel = 0  THEN EXIT

        //  Для меня новенькое - осваиваю новый тип блока обработки
        SWITCH nSel
        CASE 1          //  Открыть смену - выставляю глобальный флаг
            pOpenSmena()
        CASE 3          //  Входим в режим кассира. Например для продаж
            pInpKassir()
        CASE 4          //  Продажа товаров с печатью чека - общий алгоритмический подход и описание
            pPayWar()
        CASE 5          //  Внесение или выплата денег из кассы. Делаю процедуру общего назначения с передачей пароля
            pInOutCash("30",300.00,Fyn("Вы желаете внести деньги в кассу?",cHelpc))
        CASE 9          //  Проверяем наличие открытого чека. Закрываем его. Чеки всегда нужно закрывать
            pCloseCheck()
        CASE 10         //  В случае открытой смены печатаем z-отчет
            pPrintZ()
        CASE 11         //  В случае открытой смены печатаем Х-отчет - это не закрывает смену и не гасит кассу
            pPrintX()
        DEFAULT
           EXIT
        END
    END

    
    //*** ОСВОБОЖДАЕМ ПАРОЛИ - выходим в режим выбора, чтобы кто-то под введенными паролями не сделал что нибуть нехорошее
    //  В принципе - это не освобождение паролей, а очистка установленного режима с очисткой всех свойств, включая пароли
    IF oKkm:ResetMode <> 0
        ErrMess("Ошибка при освобождении паролей. Код ошибки = "+Alltrim(Str(oKkm:ResetMode)),cError)
        RETU
    ENDI

    //*** ОСВОБОЖДАЕМ ПОРТ - освобождаем порт
    oKkm:DeviceEnabled  := FALSE
    IF oKkm:ResultCode <> 0
        ErrMess("Ошибка при освобождении ПОРТА. Код ошибки = "+Alltrim(Str(oKkm:ResultCode)),cError)
        RETU
    ENDI

    //  Очищаю объект и закрываю программу
    oKkm    := NIL
    fErrQuit("Спасибо за работу со мной!",cMainc)
    
    RETU        

****************************************************************************************************
*   НАБОР ЭЛЕМЕНТАРНЫХ ПРОЦЕДУР, ВЫЗЫВАЕМЫХ ИЗ ТЕСТОВОГО МЕНЮ ПРОГРАММЫ    
****************************************************************************************************

* --------------------------------------------------------------------------------------------------
*   Открыть смену - выставляю глобальный флаг
STAT PROC pOpenSmena()
    IF oKkm:SessionOpened
        ErrMess("Смена уже открыта!",cError)
        RETU
    ENDI
    
    //???
    RETU
    
* --------------------------------------------------------------------------------------------------    
*   Продажа товаров с печатью чека - общий алгоритмический подход и описание последовательности
/*
    Примерная последовательность вызовов:
    1.  Открыть чек
    2.  Регистрация первой позиции
    3.  Скидка на первую позицию - у меня без скидок
    4.  Регистрация второй позиции
    5.  Надбавка на весь чек
    6.  Прием оплаты
    7.  Закрытие чека
*/
STAT PROC pPayWar()
    LOCA nI:=0, nL:=0
    LOCA cPass      := "1"                  //  Пароль кассира
    LOCA aWar       := {}                   //  Список товаров для продаж, очищенный от скидок
    LOCA cCust      := "+79276214504"       //  Можно передавать или телефон (+7хххххххххх) или e-mail: test @ test.com  
    
    //  У меня будет список, созданный при формировании чека, а здесь делаю в виде массива
    aadd(aWar,{"Водка беленькая 0.4",1,320.00})
    aadd(aWar,{"Шампанское роза ветров полупьяная",2,730.00})
    aadd(aWar,{"Закусь",1.34,123.75})

    //  1.  Открытие чека. Определение пароля и задание режима работы кассы
    oKkm:Password   := cPass                //  Устанавливаем пароль кассира для режима регистрации продаж
    oKkm:Mode       := 1                    //	Входим в режим регистрации - Mode = 1
    IF oKkm:SetMode <> 0                    //  Ошибка
        ErrMess("Ошибка при установке режима регистрации. Код ошибки = "+Alltrim(Str(oKkm:SetMode)),cError)
        RETU
    ENDI
    
    //  2.  Определение свойств чека и открываю чек
    oKkm:CheckState()                       //  Определяю состояние предыдущего чека
    oKkm:CancelCheck()                      //  Для профилактики отправляю метод аннулирования "предыдущего" чека
    
    oKkm:CheckType  := 0                    //  Чек продажи
    IF oKkm:OpenCheck <> 0                  //  Открываю чек
        ErrMess("Ошибка при открытии чека. Код ошибки = "+Alltrim(Str(oKkm:OpenCheck)),cError)
        RETU
    ENDI

    //  Отправка данных о покупателе, если он это потребовал до момента создания чека и дал свои атрибуты
    oKkm:CustomerEmail  := cCust
    IF oKkm:FNSendCustomerEmail <> 0 THEN ErrMess("Ошибка отправки данных о покупателе",cError)
    
    //  3.  В цикле регистрирую каждую позицию чека
    nL              := Len(aWar)
    FOR nI := 1 TO nL
        oKkm:Name           := HB_OEMTOANSI(aWar[nI,1])         //  Наименование товара
        oKkm:Price          := aWar[nI,3]                       //  Цена, как число
        oKkm:Quantity       := aWar[nI,2]                       //  Количество - возможно дробное с точкой
        oKkm:Department     := 1                                //  Всегда указывается отдел (раздел)

        IF oKkm:Registration <> 0                               //  Регистрация строки продажи
            ErrMess("Ошибка регистрации строки продажи. Код ошибки = "+Alltrim(Str(oKkm:Registration)),cError)
        ENDI
    NEXT nI
    
    //  4.  Закрытие чека наличными без ввода полученной от клиента суммы
    oKkm:TypeClose          := 0
    IF oKkm:CloseCheck <> 0 THEN ErrMess("Ошибка при закрытии чека. Код ошибки = "+Alltrim(Str(oKkm:CloseCheck)),cError)
    RETU

* -------------------------------------------------------------------------------------------------    
*   Проверяем наличие открытого чека. Закрываем его. Чеки всегда нужно закрывать
STAT PROC pCloseCheck()
    IF oKkm:CheckState <> 0         //  Признак открытости чека
        IF oKkm:CancelCheck <> 0    //  Ошибка при закрытии чека
            ErrMess("Ошибка при попытке закрытия до этого открытого чека. Код ошибки = "+Alltrim(Str(oKkm:CancelCheck)),cError)
            RETU
        ENDI
    ENDI
    RETU
    
* -------------------------------------------------------------------------------------------------    
*   В случае открытой смены печатаем z-отчет
STAT PROC pPrintZ()
    
    //	Если смена открыта снимаем Z-отчет... Наверное это просто тестовый пример, а при текущей работе данного делать не нужно и выполнять команду по отдельному заданию?
    IF !oKkm:SessionOpened
        ErrMess("Нет открытой смены! Нельзя напечатать Z-отчет!",cError)
        RETU
    ENDI
    
    //  Для снятия z-отчета необходимы права администратора. Пароли задаваеются при настройке драйвера
    oKkm:Password   := "30"     //  //  Устанавливаем пароль системного администратора ККМ (30)

    //  Входим в режим отчетов с гашением - нужно изучить все возможные параметры Mode
    oKkm:Mode       := 3
    IF oKkm:SetMode <> 0
        ErrMess("Ошибка при установке режима ККМ - отчет с гашением. Код ошибки = "+Alltrim(Str(oKkm:SetMode)),cError)
        RETU
    ENDI

    //  Снимаем z-отчет... Просто печатается на ФР (ReportType??? - тип отчета)
    oKkm:ReportType := 1
    IF oKkm:Report <> 0
        ErrMess("Ошибка отправки на печать регламентного типа отчета. Код ошибки = "+Alltrim(Str(oKkm:Report)),cError)
        RETU
    ENDI
    RETU

* --------------------------------------------------------------------------------------------------    
*   В случае открытой смены печатаем Х-отчет - это не закрывает смену и не гасит кассу???
STAT PROC pPrintX()
    
    //	Если смена открыта снимаем X-отчет без гашения...
    IF !oKkm:SessionOpened
        ErrMess("Нет открытой смены! Нельзя напечатать Z-отчет!",cError)
        RETU
    ENDI

    //	Проведение и печать Х-отчета - он вроде бы не закрывает кассовый день X - отчет
    oKkm:Password   := "29"     //  АДМИНИСТРАТОРЫ БЫВАЮТ РАЗНЫЕ! устанавливаем пароль администратора ККМ
    
    //  Входим в режим отчетов без гашения - нужно изучить все возможные параметры Mode
    oKkm:Mode       := 2
    IF oKkm:SetMode <> 0
        ErrMess("Ошибка при установке режима ККМ - отчет с гашением. Код ошибки = "+Alltrim(Str(oKkm:SetMode)),cError)
        RETU
    ENDI

    //  Снимаем X-отчет... Просто печатается на ФР (ReportType??? - тип отчета)
    oKkm:ReportType := 2
    IF oKkm:Report <> 0
        ErrMess("Ошибка отправки на печать регламентного типа отчета. Код ошибки = "+Alltrim(Str(oKkm:Report)),cError)
        RETU
    ENDI
    RETU
    
* --------------------------------------------------------------------------------------------------    
*   Внесение или выплата денег из кассы. Делаю процедуру общего назначения с передачей пароля. Эдесь
*   приведена четкая и правильная последовательность задания свойств и вызовов методов или операций
*   с анализом возникновения ошибок при их использовании
*   Параметры:
*   cPass   -   пароль для режима
*   nSum    -   сумма внесения или выплаты
*   lInCash -   ИСТИНА, если внесение, иначе выплата указанной суммы
STAT PROC pInOutCash(cPass,nSum,lInCash)
    LOCA nResult:=0
    
    //  Задаем свойства для метода SetMode
    oKkm:Password   := Alltrim(cPass)       //  Пароль для режима
    oKkm:Mode       := 1                    //  Режим регистрации = 1 (деньги и чеки)
    
    //  Попытка вызвать метод установки режима и выход при ошибке
    IF oKkm:SetMode <> 0
        ErrMess("Ошибка при установке режима ККМ - регистрация. Код ошибки = "+Alltrim(Str(oKkm:SetMode)),cError)
        RETU
    ENDI
    
    //  Меняю только свойство суммы для операции
    oKkm:summ       := nSum
    
    //  Вызываю операцию и определяю код возвращаемой ошибки, если таковая будет
    nResult         := IF( lInCash, oKkm:CashInCome, oKkm:CashOutCome )
    
    //  Даём только сообщение, т.к. нужно ещё будет очистить свойства режима
    IF nResult <> 0 THEN ErrMess("Ошибка при регистрации с внесением или выдачей денег. Код ошибки = "+Alltrim(Str(nResult)),cError)

    //  Очищаем свойства режима, в частности активные пароли на кассе
    IF oKkm:ResetMode <> 0 THEN ErrMess("Ошибка при очистке свойств режима регистрации. Код ошибки = "+Alltrim(Str(oKkm:ResetMode)),cError)
    RETU
    
* --------------------------------------------------------------------------------------------------    
*   Входим в режим кассира. Например для ввода продаж - задаётся пароль кассира и получаем допуск
*   Все настройки (пароли) задаются в режимах настройки драйвера фискального регистратора
STAT PROC pInpKassir()
    
    //  Входим в режим регистрации пользователя на ФР. Устанавливаем пароль кассира ("1")
    oKkm:Password   := "1"

    //	Входим в режим регистрации - Mode = 1... Это работы кассира? Каждый раз нужно проверять, что команда отработала без ошибок
    oKkm:Mode       := 1
    IF oKkm:SetMode <> 0
        ErrMess("Ошибка при установке режимов ККМ - работа кассира. Код ошибки = "+Alltrim(Str(oKkm:SetMode)),cError)
        RETU
    ENDI
    RETU
Часовой пояс GMT +3, время: 10:30.

Форум на базе vBulletin®
Copyright © Jelsoft Enterprises Ltd.
В случае заимствования информации гипертекстовая индексируемая ссылка на Форум обязательна.