Compare commits

...

55 Commits

Author SHA1 Message Date
leca 5f4a86cee8 versioning 2025-04-01 20:55:12 +03:00
leca a73bf1fc53 translations and cleanup 2025-04-01 18:10:49 +03:00
leca 7275892b04 remove obsolete settings 2025-04-01 18:03:30 +03:00
leca e749c21a61 remove unneeded code. 2025-04-01 17:50:02 +03:00
leca f483c97935 wrap with tr 2025-03-30 21:26:41 +03:00
leca dda40e11b8 do not accept rich text in email scene 2025-03-30 21:05:07 +03:00
leca 7822984ff0 cleanup 2025-03-30 20:51:52 +03:00
leca c17af59358 add autodetect in ocr scene 2025-03-30 20:50:11 +03:00
leca 6b815dbe0a added store autodetect in email scene 2025-03-30 20:48:53 +03:00
leca 5600e03ce1 fixed wrong versions 2025-03-30 12:25:56 +03:00
leca 7d71cb016a translations 2025-03-26 20:14:14 +03:00
leca 7a52905cff download modules 2025-03-26 20:08:54 +03:00
leca 3b26dbc29d replace commas to periods as separators for decimal numbers 2025-03-26 00:20:43 +03:00
leca 754700edfb fixed source 2025-03-25 21:16:33 +03:00
leca 9094d3c997 settings icon and CMakeLists.txt fixes 2025-03-25 21:13:27 +03:00
leca 1b32774e55 bugfixes 2025-03-24 02:02:10 +03:00
leca d17695a7fa settings and bugfixes 2025-03-23 20:55:34 +03:00
leca e58d6068e0 checks-parser-git done, checks-parser-bin WIP 2025-03-23 18:48:17 +03:00
leca 80e9397e01 automated .deb packaging 2025-03-22 14:50:51 +03:00
leca ba8fc1079a based deployment structure 2025-03-22 14:07:10 +03:00
leca e49a078c80 stable appimage deployment done 2025-03-22 12:52:48 +03:00
leca 64f081b522 cleanup 2025-03-22 01:38:28 +03:00
leca b19c92079d support old cmake versions with finding boost 2025-03-22 01:38:14 +03:00
leca a342d78df7 deployment 2025-03-22 01:19:53 +03:00
leca 59315f9445 net weights implementation WIP 2025-03-22 01:02:37 +03:00
leca d83f106a91 migrate to boost::regex 2025-03-21 22:43:44 +03:00
leca 1fa69c3a69 tolerate old version of hlohmann::json 2025-03-21 21:50:08 +03:00
leca 89afe836be todo 2025-03-21 00:46:17 +03:00
leca 51d8600be0 Deployment 2025-03-21 00:23:38 +03:00
leca 229a6bcc9e right dependency division 2025-03-20 22:01:53 +03:00
leca 17fd9da3e6 removed cpp-httplib dependency 2025-03-20 22:00:19 +03:00
leca 33f819a09d cleanup 2025-03-18 00:02:10 +03:00
leca a87869ca7f fixed wrong name 2025-03-17 23:41:46 +03:00
leca b57a542161 rewrite utils with moduled approach, butfixes 2025-03-17 23:39:08 +03:00
leca b966d7fcf5 implemented modular build for email text and ocr 2025-03-17 23:18:35 +03:00
leca cb8041c928 divide ways of input in CMakeLists 2025-03-17 22:55:36 +03:00
leca 5209b7bf22 fixed bug with server not listening messages on first export and added a button to stop the server 2025-03-17 22:08:38 +03:00
leca b86514b030 update debian-based installation of dependencies 2025-03-17 20:18:12 +03:00
leca 31f4ca26fb cleanup 2025-03-17 20:16:34 +03:00
leca 993cf4d69c httplib version bump and automated (docker) appimage deployment 2025-03-17 20:13:44 +03:00
leca 487707ba3e deployment 2025-03-17 00:06:19 +03:00
leca 3dbc85f929 generate and show qr code 2025-03-15 15:12:53 +03:00
leca 2b2127e3b5 restructure, change onDataDecode signal and succesfully parsing http request 2025-03-15 00:48:46 +03:00
leca f507ec8d67 starting http server with error handling 2025-03-14 18:24:42 +03:00
leca 453f907bfa Merge pull request 'UI rework' (#3) from ui_rework into master 2025-03-14 01:27:59 +03:00
leca 39c4bfb2fd fixed translations 2025-03-14 01:12:55 +03:00
leca 33b54fb475 added ofd scene, working http server 2025-03-14 00:44:14 +03:00
leca b305fba2fd russian grammar 2025-03-12 12:53:43 +03:00
leca 1ae724f925 added functionality to email text and ocr scenes 2025-03-11 23:31:08 +03:00
leca 4c7a25c53e added ui for ofd 2025-03-11 19:37:58 +03:00
leca cb3d6c2a3f rework ui, add text from email scene 2025-03-09 21:23:36 +03:00
leca 4f75e88b69 staging 2025-03-09 17:11:34 +03:00
leca 29b9b58759 rework of mainwindow in progress 2025-03-09 16:05:37 +03:00
leca df522f07f7 merge 2025-03-08 17:35:05 +03:00
leca 05563a5f82 removed unneeded dependency from readme 2025-03-03 23:26:14 +03:00
74 changed files with 3500 additions and 2078 deletions

3
.env Normal file
View File

@ -0,0 +1,3 @@
name=checks-parser
version=alpha_0.0.4
revision=1

2
.gitignore vendored
View File

@ -124,3 +124,5 @@ checks-parser
deploy/appimage/AppDir/usr/share/doc/ deploy/appimage/AppDir/usr/share/doc/
deploy/appimage/AppDir/usr/share/ deploy/appimage/AppDir/usr/share/
*.deb *.deb
binaries

View File

@ -1,63 +1,122 @@
cmake_minimum_required(VERSION 3.10) cmake_minimum_required(VERSION 3.10)
project(checks-parser VERSION 0.1 LANGUAGES CXX) project(checks-parser VERSION 0.0.4 LANGUAGES CXX)
option(BUILD_TRANSLATIONS "Build translations?" ON) option(BUILD_TRANSLATIONS "Build translations?" ON)
option(BUILD_EMAIL_MODE "Build email mode?" ON)
option(BUILD_OFD_LOCAL_QR_SCAN "Build OFDs' local qr scanner?" ON)
option(BUILD_OFD_BINARYEYE_SCAN "Build OFDs' binaryeye scanner?" ON)
if (NOT (BUILD_EMAIL_MODE OR BUILD_OFD_LOCAL_QR_SCAN OR BUILD_OFD_BINARYEYE_SCAN))
message(FATAL_ERROR "You must specify at least one of the modes of data input!")
return()
endif()
if (BUILD_TRANSLATIONS)
if(CMAKE_VERSION VERSION_LESS 3.12)
add_definitions(-DBUILD_TRANSLATIONS)
else()
add_compile_definitions(BUILD_TRANSLATIONS)
endif()
endif()
if (BUILD_OFD_LOCAL_QR_SCAN OR BUILD_OFD_BINARYEYE_SCAN)
if(CMAKE_VERSION VERSION_LESS 3.12)
add_definitions(-DBUILD_OFD_MODE)
else()
add_compile_definitions(BUILD_OFD_MODE)
endif()
endif()
if (BUILD_EMAIL_MODE)
if(CMAKE_VERSION VERSION_LESS 3.12)
add_definitions(-DBUILD_EMAIL_MODE)
else()
add_compile_definitions(BUILD_EMAIL_MODE)
endif()
endif()
if (BUILD_OFD_LOCAL_QR_SCAN)
if(CMAKE_VERSION VERSION_LESS 3.12)
add_definitions(-DBUILD_OFD_LOCAL_QR_SCAN)
else()
add_compile_definitions(BUILD_OFD_LOCAL_QR_SCAN)
endif()
endif()
if (BUILD_OFD_BINARYEYE_SCAN)
if(CMAKE_VERSION VERSION_LESS 3.12)
add_definitions(-DBUILD_OFD_BINARYEYE_SCAN)
else()
add_compile_definitions(BUILD_OFD_BINARYEYE_SCAN)
endif()
endif()
SET(CMAKE_BUILD_TYPE Debug)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC OFF) set(CMAKE_AUTORCC OFF)
set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOUIC_SEARCH_PATHS Designer) set(CMAKE_AUTOUIC_SEARCH_PATHS scenes)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt5Core REQUIRED) find_package(Qt5Core REQUIRED)
find_package(Qt5 REQUIRED COMPONENTS LinguistTools) if (BUILD_TRANSLATIONS)
find_package(Qt5 REQUIRED COMPONENTS LinguistTools)
endif()
find_package(Qt5Gui REQUIRED) find_package(Qt5Gui REQUIRED)
find_package(Qt5Widgets REQUIRED) find_package(Qt5Widgets REQUIRED)
set(PROJECT_SOURCES set(TRANSLATION_SOURCES
main.cpp main.cpp
mainwindow.cpp mainwindow.cpp mainwindow.h scenes/mainwindow.ui
mainwindow.h outputdialog.h outputdialog.cpp scenes/outputdialog.ui
mainwindow.ui settingsdialog.h settingsdialog.cpp scenes/settingsdialog.ui
)
if (BUILD_OFD_LOCAL_QR_SCAN)
list(APPEND TRANSLATION_SOURCES adjustpicturedialog.h adjustpicturedialog.cpp scenes/adjustpicturedialog.ui)
endif()
if (BUILD_OFD_LOCAL_QR_SCAN OR BUILD_OFD_BINARYEYE_SCAN)
list(APPEND TRANSLATION_SOURCES solvecaptchadialog.h solvecaptchadialog.cpp scenes/solvecaptchadialog.ui)
endif()
set(PROJECT_SOURCES
goods/goods.h goods/goods.cpp goods/goods.h goods/goods.cpp
check/check.h check/check.cpp check/check.h check/check.cpp
parser/parser.h parser/parser.cpp
parser/module.h parser/module.cpp
outputdialog.h outputdialog.cpp outputdialog.ui
output/output_options.h output/output_options.cpp output/output_options.h output/output_options.cpp
utils/utils.h utils/utils.cpp utils/utils.h utils/utils.cpp
image/checkimage.h image/checkimage.cpp
net/net.h net/net.cpp net/net.h net/net.cpp
settings/settings.h settings/settings.cpp settings/settings.h settings/settings.cpp
settingsdialog.h settingsdialog.cpp settingsdialog.ui
adjustpicturedialog.h adjustpicturedialog.cpp adjustpicturedialog.ui ${TRANSLATION_SOURCES}
image_redactor/imageredactor.h image_redactor/imageredactor.cpp
solvecaptchadialog.h solvecaptchadialog.cpp solvecaptchadialog.ui
exceptions/ofdrequestexception.h exceptions/ofdrequestexception.cpp
) )
set(TRANSLATION_SOURCES if (BUILD_OFD_LOCAL_QR_SCAN)
main.cpp list(APPEND PROJECT_SOURCES image_redactor/imageredactor.h image_redactor/imageredactor.cpp)
mainwindow.cpp mainwindow.h mainwindow.ui endif()
outputdialog.cpp outputdialog.h outputdialog.ui
settingsdialog.cpp settingsdialog.h settingsdialog.ui
solvecaptchadialog.cpp solvecaptchadialog.h solvecaptchadialog.ui
adjustpicturedialog.cpp adjustpicturedialog.h adjustpicturedialog.ui
)
set(TS_FILES if (BUILD_OFD_BINARYEYE_SCAN OR BUILD_OFD_LOCAL_QR_SCAN)
translations/en_US.ts list(APPEND PROJECT_SOURCES exceptions/ofdrequestexception.h exceptions/ofdrequestexception.cpp)
translations/ru_RU.ts endif()
)
if (BUILD_OFD_BINARYEYE_SCAN)
list(APPEND PROJECT_SOURCES http_server/http_server.h http_server/http_server.cpp)
endif()
if (BUILD_TRANSLATIONS) if (BUILD_TRANSLATIONS)
set(TS_FILES
translations/en_US.ts
translations/ru_RU.ts
)
qt5_create_translation(QM_FILES "${TRANSLATION_SOURCES}" ${TS_FILES}) qt5_create_translation(QM_FILES "${TRANSLATION_SOURCES}" ${TS_FILES})
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/translations.qrc ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/translations.qrc ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc COPYONLY)
qt5_add_resources(TRANSLATIONQRC ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc) qt5_add_resources(TRANSLATIONQRC ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc)
@ -66,7 +125,23 @@ if (BUILD_TRANSLATIONS)
add_dependencies(resources translations) add_dependencies(resources translations)
endif() endif()
# Media QRC
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/media.qrc ${CMAKE_CURRENT_BINARY_DIR}/media.qrc COPYONLY)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/assets DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
qt5_add_resources(MEDIAQRC ${CMAKE_CURRENT_BINARY_DIR}/media.qrc)
add_custom_target(mediaresource ALL DEPENDS ${MEDIAQRC})
#Scenes QRC
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scenes.qrc ${CMAKE_CURRENT_BINARY_DIR}/scenes.qrc COPYONLY)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/scenes DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
qt5_add_resources(SCENESQRC ${CMAKE_CURRENT_BINARY_DIR}/scenes.qrc)
add_custom_target(scenessource ALL DEPENDS ${SCENESQRC})
set(SOURCES "") set(SOURCES "")
list(APPEND SOURCES ${MEDIAQRC})
list(APPEND SOURCES ${SCENESQRC})
if (BUILD_TRANSLATIONS) if (BUILD_TRANSLATIONS)
list(APPEND SOURCES ${TRANSLATIONQRC}) list(APPEND SOURCES ${TRANSLATIONQRC})
endif() endif()
@ -85,7 +160,9 @@ endif()
target_link_libraries(checks-parser PRIVATE Qt5::Widgets) target_link_libraries(checks-parser PRIVATE Qt5::Widgets)
target_include_directories(checks-parser PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/image_redactor) if (BUILD_OFD_LOCAL_QR_SCAN)
target_include_directories(checks-parser PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/image_redactor)
endif()
set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER org.foxarmy.checks-parser) set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER org.foxarmy.checks-parser)
@ -104,20 +181,39 @@ install(TARGETS checks-parser
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
) )
if(WIN32) if(WIN32)
#???? #????
set(OpenCV_DIR /usr/local/lib/cmake/opencv4) set(OpenCV_DIR /usr/local/lib/cmake/opencv4)
endif() endif()
find_package(OpenCV REQUIRED COMPONENTS core imgproc imgcodecs) if (BUILD_OFD_BINARYEYE_SCAN)
find_package(PkgConfig)
pkg_check_modules(QRENCODE REQUIRED libqrencode)
include_directories(${QRENCODE_INCLUDE_DIRS})
link_directories(${QRENCODE_LIBRARY_DIRS})
target_link_libraries(checks-parser PRIVATE ${QRENCODE_LIBRARIES})
endif()
if (BUILD_OFD_LOCAL_QR_SCAN)
target_link_libraries(checks-parser PRIVATE -lzbar)
endif()
include_directories( ${OpenCV_INCLUDE_DIRS} )
target_link_libraries(checks-parser PRIVATE -lzbar)
target_link_libraries(checks-parser PRIVATE -ltesseract)
target_link_libraries(checks-parser PRIVATE -lcurl) target_link_libraries(checks-parser PRIVATE -lcurl)
target_link_libraries(checks-parser PRIVATE ${OpenCV_LIBS} )
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8) if (CMAKE_VERSION VERSION_LESS 3.30)
find_package(Boost 1.45.0 REQUIRED COMPONENTS regex)
else()
find_package(Boost 1.45.0 CONFIG REQUIRED COMPONENTS regex)
endif()
include_directories(${Boost_INCLUDE_DIRS})
target_link_libraries(checks-parser PUBLIC ${Boost_LIBRARIES})
if (BUILD_OFD_LOCAL_QR_SCAN OR BUILD_OFD_BINARYEYE_SCAN)
find_package(OpenCV REQUIRED COMPONENTS core imgproc imgcodecs)
target_link_libraries(checks-parser PRIVATE ${OpenCV_LIBS})
target_include_directories(checks-parser PUBLIC ${OpenCV_INCLUDE_DIRS})
include_directories( ${OpenCV_INCLUDE_DIRS} )
endif()
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9)
target_link_libraries(checks-parser PRIVATE -lstdc++fs) target_link_libraries(checks-parser PRIVATE -lstdc++fs)
endif() endif()

View File

@ -23,12 +23,14 @@ To export, you need to specify an output file path and, if you wish, you can cha
# Installing # Installing
## Building ## Building
In general, you need to install following dependencies in order to build that app(I suppose you have installed all the build necessaries such as cmake, make, gcc, git, etc...): In general, you need to install following dependencies in order to build that app(I suppose you have installed all the build necessaries such as cmake, make, gcc, git, etc...):
* boost
* tesseract (you also have to install appropriate for your needs language data) * tesseract (you also have to install appropriate for your needs language data)
* opencv * opencv
* zbar * zbar
* curl * curl
* nlohmann-json * nlohmann-json
* qt5 * qt5
* qrencode
Please, do not hesitate to open an issue if you cannot build that. I will help and if you are building on a distro that is not listed there, we can append that list as soon as we will solve your problem! Please, do not hesitate to open an issue if you cannot build that. I will help and if you are building on a distro that is not listed there, we can append that list as soon as we will solve your problem!
### Linux ### Linux
@ -36,7 +38,7 @@ Please, do not hesitate to open an issue if you cannot build that. I will help a
I recommend using aur helper (I use yay) to install dependencies. Or, if you're masochist, you can build all by yourself ¯\\\_(ツ)\_/¯ I recommend using aur helper (I use yay) to install dependencies. Or, if you're masochist, you can build all by yourself ¯\\\_(ツ)\_/¯
``` ```
#Install dependencies #Install dependencies
yay -S base-devel qt5-base opencv zbar nlohmann-json tesseract yay -S base-devel qt5-base opencv zbar nlohmann-json tesseract qrencode boost
#Install a language package for OCR. Replace ``LANG` to your language. For example, ``tesseract-data-rus`` for russian language #Install a language package for OCR. Replace ``LANG` to your language. For example, ``tesseract-data-rus`` for russian language
yay -S tesseract-data-LANG yay -S tesseract-data-LANG
#Clone and compile an app #Clone and compile an app
@ -52,9 +54,9 @@ In debian-based distributions most, but not every, package names are the same.
Installation of dependencies for different debian-based distros: Installation of dependencies for different debian-based distros:
###### Ubuntu 18.04 ###### Ubuntu 18.04
```apt install -y qtbase5-dev openssl libmbedtls-dev tesseract-ocr tesseract-ocr-rus libopencv-dev libzbar-dev qttools5-dev nlohmann-json-dev libcurl4-openssl-dev libtesseract-dev``` ```apt install -y qtbase5-dev openssl libmbedtls-dev tesseract-ocr tesseract-ocr-rus libopencv-dev libzbar-dev qttools5-dev nlohmann-json-dev libcurl4-openssl-dev libtesseract-dev libqrencode-dev libboost-regex-dev```
###### Ubuntu 20.04, LMDE (tested only 6), Debian (tested only 12) ###### Ubuntu 20.04, LMDE (tested only 6), Debian (tested only 12)
```apt install -y qtbase5-dev openssl libmbedtls-dev tesseract-ocr tesseract-ocr-rus libopencv-dev libzbar-dev qttools5-dev nlohmann-json3-dev libcurl4-openssl-dev libtesseract-dev``` ```apt install -y qtbase5-dev openssl libmbedtls-dev tesseract-ocr tesseract-ocr-rus libopencv-dev libzbar-dev qttools5-dev nlohmann-json3-dev libcurl4-openssl-dev libtesseract-dev libqrencode-dev libboost-regex-dev```
Next steps are identical for every debian-based distro Next steps are identical for every debian-based distro
``` ```

View File

@ -4,31 +4,33 @@
Чек парсер - это приложение, позволяющее доставать содержимое чека и переводить его в .csv файлы. Чек парсер - это приложение, позволяющее доставать содержимое чека и переводить его в .csv файлы.
!!!НА ДАННЫЙ МОМЕНТ ПОДДЕРЖИВАЮТСЯ ТОЛЬКО РУССКИЕ ЧЕКИ!!! !!!НА ДАННЫЙ МОМЕНТ ПОДДЕРЖИВАЮТСЯ ТОЛЬКО РУССКИЕ ЧЕКИ!!!
Чтобы узнать, почему [смотрите здесь](https://git.foxarmy.org/leca/checks-parser/src/branch/master/README.ru.md#checks-from-different-countries) Чтобы узнать почему [смотрите здесь](https://git.foxarmy.org/leca/checks-parser/src/branch/master/README.ru.md#checks-from-different-countries)
# Пользование # Пользование
Для более детального описания, пожалуйста, обратитесь к [вики](https://git.foxarmy.org/leca/checks-parser/wiki/Description-%5BRU%5D) Для более детального описания, пожалуйста, обратитесь к [вики](https://git.foxarmy.org/leca/checks-parser/wiki/Description-%5BRU%5D)
### Ввод данных ### Ввод данных
Доступны следующие способы ввода данных: Доступны следующие способы ввода данных:
* Через изображениие (используется OCR(Optical Character Recognition, Оптическое распознавание символов) чтобы прочитать содержимое чека. Изображение чека должно быть контрастным и выровненным (текст обязан быть перпендикулярным к границам изображения) хорошо, чтобы нормально прочитаться.) OCR - не волшебная палочка :( * Через изображениие (используется OCR(Optical Character Recognition, Оптическое распознавание символов), чтобы прочитать содержимое чека. Изображение чека должно быть контрастным и выровненным (текст обязан быть перпендикулярным к границам изображения) хорошо, чтобы нормально прочитаться. OCR - не волшебная палочка :(
* Через просто текст, скопированный из эл. письма. Просто скопируйте и вставьте текст с вашего письма, выберите подходящий магазин (автодетект в планах!) и парсите. * Через простой текст, скопированный из эл. письма. Скопируйте и вставьте текст с вашего письма, выберите подходящий магазин (автодетект в планах!) и парсите.
* Через QRCode на чеке (этот метод запрашивает данные у ОФД (Оператор Фискальных Данных) (В данном конкретном случае, к ofd.ru)). * Через QRCode на чеке (этот метод запрашивает данные у ОФД (Оператор Фискальных Данных), в данном конкретном случае, к ofd.ru).
### Вывод данных ### Вывод данных
На начальном этапе разработки программы, Я задумывался о 3 или более форматов вывода: csv, xlsx и ods. Но по мере разработки, я понял, что большинство современных табличных процессоров (электронных таблиц) способны импортировать в себя csv гораздо лучше, чем смог бы написать я сам. Так что я решил не делать вывод во все остальные форматы, кроме csv. На начальном этапе разработки программы, Я задумывался о 3-х или более форматов вывода: csv, xlsx и ods. Но, по мере разработки, я понял, что большинство современных табличных процессоров (электронных таблиц) способны импортировать в себя csv гораздо лучше, чем смог бы написать я сам. Так что я решил не делать вывод во все остальные форматы, кроме csv.
Чтобы экспортировать, вам нужно указать путь до файла, если вы желаете, вы можете изменить порядок и/или переименовать (алиасы) столбцы, выбрать печатать или не печатать заголовок (алиасы столбцов) и "итого" Чтобы экспортировать вам нужно: указать путь до файла, если вы желаете, вы можете изменить порядок и/или переименовать (алиасы) столбцы, выбрать печатать или не печатать заголовок (алиасы столбцов) и "итого".
# Установка # Установка
## Сборка из исходников ## Сборка из исходников
В целом, вам нужно установить следующие зависимости чтобы собрать приложение (я предполагаю, что вы уже имеете на системе базовые пакеты вроде cmake, make, gcc, git и так далее): В целом, вам нужно установить следующие зависимости, чтобы собрать приложение (я предполагаю, что вы уже имеете на системе базовые пакеты вроде cmake, make, gcc, git и так далее):
* boost
* tesseract (также вам нужно будет установить языковой пакет для него, например tesseract-data-rus на Arch Linux или tesseract-ocr-rus на Debian Linux.) * tesseract (также вам нужно будет установить языковой пакет для него, например tesseract-data-rus на Arch Linux или tesseract-ocr-rus на Debian Linux.)
* opencv * opencv
* zbar * zbar
* curl * curl
* nlohmann-json * nlohmann-json
* qt5 * qt5
* qrencode
Пожалуйста, не стесняйтесь и открывайте issue, если вы не можете собрать приложение. Я помогу вам, и если вы собираете приложение на дистрибутиве, который здесь не перечислен, как только мы решим вашу проблему, я добавлю новый дистрибутив в этот список! Пожалуйста, не стесняйтесь и открывайте issue, если вы не можете собрать приложение. Я помогу вам, и если вы собираете приложение на дистрибутиве, который здесь не перечислен, как только мы решим вашу проблему, я добавлю новый дистрибутив в этот список!
@ -37,7 +39,7 @@
Я рекомендую использовать помощник для АУРа (я использую yay) чтобы установить зависимости. Или, если вы мазохист, можете собрать все зависимости ручками ¯\\\_(ツ)\_/¯ Я рекомендую использовать помощник для АУРа (я использую yay) чтобы установить зависимости. Или, если вы мазохист, можете собрать все зависимости ручками ¯\\\_(ツ)\_/¯
``` ```
#Установка зависимостей #Установка зависимостей
yay -S base-devel qt5-base opencv zbar nlohmann-json tesseract yay -S base-devel qt5-base opencv zbar nlohmann-json tesseract qrencode boost
#Установка языкового пакета для OCR. Замените ``LANG` на желаемый язык. Например, ``tesseract-data-rus`` для русского языка #Установка языкового пакета для OCR. Замените ``LANG` на желаемый язык. Например, ``tesseract-data-rus`` для русского языка
yay -S tesseract-data-LANG yay -S tesseract-data-LANG
#Загрузка исходгого кода и сборка приложения #Загрузка исходгого кода и сборка приложения
@ -53,9 +55,9 @@ sudo make install
Установка зависимостей для различных debian дистрибутивов: Установка зависимостей для различных debian дистрибутивов:
###### Ubuntu 18.04 ###### Ubuntu 18.04
```apt install -y qtbase5-dev openssl libmbedtls-dev tesseract-ocr tesseract-ocr-rus libopencv-dev libzbar-dev qttools5-dev nlohmann-json-dev libcurl4-openssl-dev libtesseract-dev``` ```apt install -y qtbase5-dev openssl libmbedtls-dev tesseract-ocr tesseract-ocr-rus libopencv-dev libzbar-dev qttools5-dev nlohmann-json-dev libcurl4-openssl-dev libtesseract-dev libqrencode-dev libboost-regex-dev```
###### Ubuntu 20.04, LMDE (проверил только 6), Debian (проверил только 12) ###### Ubuntu 20.04, LMDE (проверил только 6), Debian (проверил только 12)
```apt install -y qtbase5-dev openssl libmbedtls-dev tesseract-ocr tesseract-ocr-rus libopencv-dev libzbar-dev qttools5-dev nlohmann-json3-dev libcurl4-openssl-dev libtesseract-dev``` ```apt install -y qtbase5-dev openssl libmbedtls-dev tesseract-ocr tesseract-ocr-rus libopencv-dev libzbar-dev qttools5-dev nlohmann-json3-dev libcurl4-openssl-dev libtesseract-dev libqrencode-dev libboost-regex-dev```
Следующие шаги идеинтичны для всех дистрибутивов, основанных на debian: Следующие шаги идеинтичны для всех дистрибутивов, основанных на debian:
``` ```

30
TODO
View File

@ -1,30 +0,0 @@
Complete module "export": [done]
make UI; [done]
make export to .csv [done]
Complete module "image-to-text": [done]
make UI; [done]
make use of tesseract/opencv (https://learnopencv.com/deep-learning-based-text-recognition-ocr-using-tesseract-and-opencv/); [done]
Add features:
autodetect store type
auto download of stores modules [done]
auto download of ofd modules [done]
settings, a window for editing settings. [done]
add ability to control contrast and rotation of a check image before passing it to OCR [done]
add ability to scan a qr code and request data from ofd.ru [done]
add ability to change language from preferences
Refactor:
Get rid of CPR, use libcurl instead [done]
Build:
Write script for AppImage deployment [done]
Find out dependencies packet names on different distros [done for arch, ubuntu]
Ensure success of building on most popular distros [done for arch, ubuntu]
Try to compile it on Windows
Issues:
Captcha is not showing when running in appimage [solved]
Stores modules are not being downloaded
I need to pack tesseract data for ru, en [solved]

View File

@ -41,7 +41,13 @@ void AdjustPictureDialog::accept() {
infoDialog.setWindowTitle(tr("No QR code")); infoDialog.setWindowTitle(tr("No QR code"));
infoDialog.exec(); infoDialog.exec();
} else { } else {
emit decodedData(result); std::map<std::string, std::string> paramsMap;
std::vector<std::string> dataSplit = split(result, "&");
for (std::string &pair : dataSplit) {
std::vector<std::string> values = split(pair, "=");
paramsMap.insert(std::pair<std::string, std::string>(values[0], values[1]));
}
emit decodedData(paramsMap);
QDialog::accept(); QDialog::accept();
} }

View File

@ -22,7 +22,7 @@ public:
void computeContrastLookupTable(); void computeContrastLookupTable();
std::vector<unsigned short> contrastLUT[100]; std::vector<unsigned short> contrastLUT[100];
signals: signals:
void decodedData(std::string data); void decodedData(std::map<std::string, std::string> data);
private slots: private slots:

131
assets/icons/OCR.svg Normal file
View File

@ -0,0 +1,131 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="159.62572mm"
height="146.77805mm"
viewBox="0 0 159.62572 146.77805"
version="1.1"
id="svg1"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
sodipodi:docname="OCR.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="true"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="0.50000001"
inkscape:cx="187"
inkscape:cy="261.99999"
inkscape:window-width="1920"
inkscape:window-height="1029"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="layer4" />
<defs
id="defs1">
<linearGradient
id="swatch50"
inkscape:swatch="solid">
<stop
style="stop-color:#00b2c3;stop-opacity:0;"
offset="0"
id="stop50" />
</linearGradient>
<linearGradient
id="linearGradient5"
inkscape:collect="always">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop5" />
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop6" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient5"
id="radialGradient6"
cx="178.3111"
cy="60.733166"
fx="178.3111"
fy="60.733166"
r="14.328103"
gradientTransform="matrix(1,0,0,0.566866,0,26.305599)"
gradientUnits="userSpaceOnUse" />
</defs>
<g
inkscape:groupmode="layer"
id="layer4"
inkscape:label="eye"
transform="translate(-20.738154,-52.70636)">
<ellipse
style="display:none;fill:#ffffff;fill-opacity:1;stroke:url(#radialGradient6);stroke-width:0.418956;stroke-opacity:1"
id="ellipse5"
ry="7.9126363"
rx="16.896055"
cy="60.733166"
cx="178.3111"
inkscape:label="inner" />
<path
id="path48"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999;stroke-dasharray:none;stroke-opacity:1"
d="m 163.03445,62.853096 c -5.5416,0.04533 -10.97868,2.888123 -16.31735,8.383468 -0.12314,0.157876 0.0243,0.318843 0.0243,0.318843 11.50919,11.568278 22.55969,11.493788 33.23673,0 0.18303,-0.169745 0.18055,-0.163774 -0.005,-0.331246 -5.75329,-5.664436 -11.39834,-8.416392 -16.93902,-8.371065 z"
inkscape:label="outer"
sodipodi:nodetypes="sccccss" />
<ellipse
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.0723045"
id="ellipse4"
inkscape:label="pupil"
ry="1.7112623"
rx="1.9444314"
cy="72.71582"
cx="160.92181" />
</g>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-20.738154,-52.70636)">
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.499999"
id="rect1"
width="101.46883"
height="146.27805"
x="21.108479"
y="52.95636"
ry="0"
inkscape:label="receipt" />
<path
style="fill:#ee0000;fill-opacity:0.51545;stroke:none;stroke-width:0.499999"
d="M 20.738154,121.46633 160.93664,72.756923 122.6633,120.9805 Z"
id="path1"
sodipodi:nodetypes="cccc"
inkscape:label="scan_ray" />
<text
xml:space="preserve"
style="font-size:13.7201px;text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.16063"
x="47.53178"
y="66.945511"
id="text2"
inkscape:label="receipt text"><tspan
sodipodi:role="line"
style="fill:#000000;fill-opacity:1;stroke-width:2.16064"
x="47.53178"
y="66.945511"
id="tspan3">Receipt</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

181
assets/icons/OFD.svg Normal file
View File

@ -0,0 +1,181 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="180.75754mm"
height="172.34297mm"
viewBox="0 0 180.75754 172.34297"
version="1.1"
id="svg1"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
sodipodi:docname="OFD.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="1.0104048"
inkscape:cx="241.98222"
inkscape:cy="365.20017"
inkscape:window-width="1920"
inkscape:window-height="1029"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1">
<marker
style="overflow:visible"
id="marker13"
refX="0"
refY="0"
orient="auto-start-reverse"
inkscape:stockid="Wide arrow"
markerWidth="1"
markerHeight="1"
viewBox="0 0 1 1"
inkscape:isstock="true"
inkscape:collect="always"
preserveAspectRatio="xMidYMid">
<path
style="fill:none;stroke:context-stroke;stroke-width:1;stroke-linecap:butt"
d="M 3,-3 0,0 3,3"
transform="rotate(180,0.125,0)"
sodipodi:nodetypes="ccc"
id="path13" />
</marker>
<marker
style="overflow:visible"
id="ArrowWide"
refX="0"
refY="0"
orient="auto-start-reverse"
inkscape:stockid="Wide arrow"
markerWidth="1"
markerHeight="1"
viewBox="0 0 1 1"
inkscape:isstock="true"
inkscape:collect="always"
preserveAspectRatio="xMidYMid">
<path
style="fill:none;stroke:context-stroke;stroke-width:1;stroke-linecap:butt"
d="M 3,-3 0,0 3,3"
transform="rotate(180,0.125,0)"
sodipodi:nodetypes="ccc"
id="path1" />
</marker>
</defs>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-12.622354,-8.2059073)">
<g
id="g3"
inkscape:label="laptop"
transform="translate(3.1423049,5.2371749)">
<rect
style="fill:#ffffff;stroke:#000000;stroke-width:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
id="rect1"
width="83.00206"
height="51.927536"
x="12.220698"
y="109.98628"
ry="2.8804462" />
<rect
style="fill:#ffffff;stroke:#000000;stroke-width:4;stroke-dasharray:none"
id="rect2"
width="85.730049"
height="4.8142142"
x="11.480049"
y="168.4975"
ry="2.4071071" />
<rect
style="fill:#ffffff;stroke:#000000;stroke-width:0;stroke-dasharray:none"
id="rect3"
width="8.389514"
height="1.2071242"
x="49.959942"
y="161.32069"
ry="0.60356212" />
</g>
<path
id="rect5"
style="fill:#ffffff;stroke:#000000;stroke-width:1.77913;stroke-dasharray:none"
d="m 135.00181,57.565658 c -1.57959,0 -2.85099,1.271404 -2.85099,2.850988 v 8.277531 c 0,1.579585 1.2714,2.851506 2.85099,2.851506 h 26.56478 v 3.891752 h -26.56478 c -1.57959,0 -2.85099,1.271404 -2.85099,2.850989 v 8.277531 c 0,1.579586 1.2714,2.851506 2.85099,2.851506 h 26.56478 v 3.575495 h -26.56478 c -1.57959,0 -2.85099,1.27141 -2.85099,2.85099 v 8.277534 c 0,1.57959 1.2714,2.85151 2.85099,2.85151 h 26.56478 v 7.61504 a 4.0588107,4.0588107 0 0 0 -1.20923,0.30489 4.0588107,4.0588107 0 0 0 -2.42569,3.32434 h -23.53344 c -1.66831,0 -3.01119,0.24778 -3.01119,0.55552 0,0.30774 1.34288,0.55552 3.01119,0.55552 h 23.57478 a 4.0588107,4.0588107 0 0 0 0.25477,0.88936 l 0.0114,0.0269 a 4.0588107,4.0588107 0 0 0 5.33611,2.10065 4.0588107,4.0588107 0 0 0 2.38073,-3.01688 h 23.52311 c 1.6683,0 3.01119,-0.24778 3.01119,-0.55552 0,-0.30774 -1.34289,-0.55552 -3.01119,-0.55552 h -23.48177 a 4.0588107,4.0588107 0 0 0 -0.31161,-1.20406 4.0588107,4.0588107 0 0 0 -3.20239,-2.40864 v -7.63157 h 26.2816 c 1.57959,0 2.85099,-1.27192 2.85099,-2.85151 v -8.277534 c 0,-1.57958 -1.2714,-2.85099 -2.85099,-2.85099 h -26.2816 v -3.575495 h 26.2816 c 1.57959,0 2.85099,-1.27192 2.85099,-2.851506 v -8.277531 c 0,-1.579585 -1.2714,-2.850989 -2.85099,-2.850989 h -26.2816 v -3.891752 h 26.2816 c 1.57959,0 2.85099,-1.271921 2.85099,-2.851506 v -8.277561 c 0,-1.579584 -1.2714,-2.850988 -2.85099,-2.850988 z"
inkscape:label="OFD" />
<path
id="path9"
style="fill:#ffffff;stroke:#000000;stroke-width:1.77913;stroke-dasharray:none"
d="m 34.83473,9.0954723 c -1.57959,0 -2.85099,1.2714037 -2.85099,2.8509877 v 8.277531 c 0,1.579585 1.2714,2.851506 2.85099,2.851506 h 26.56478 v 3.891752 H 34.83473 c -1.57959,0 -2.85099,1.271404 -2.85099,2.850989 v 8.277531 c 0,1.579586 1.2714,2.851506 2.85099,2.851506 H 61.39951 V 44.52277 H 34.83473 c -1.57959,0 -2.85099,1.27141 -2.85099,2.85099 v 8.27753 c 0,1.57959 1.2714,2.85151 2.85099,2.85151 h 26.56478 v 7.61504 a 4.0588107,4.0588107 0 0 0 -1.20923,0.30489 4.0588107,4.0588107 0 0 0 -2.42569,3.32434 H 34.23115 c -1.66831,0 -3.01119,0.24778 -3.01119,0.55552 0,0.30774 1.34288,0.55552 3.01119,0.55552 h 23.57478 a 4.0588107,4.0588107 0 0 0 0.25477,0.88936 l 0.0114,0.0269 a 4.0588107,4.0588107 0 0 0 5.33611,2.10065 4.0588107,4.0588107 0 0 0 2.38073,-3.01688 h 23.523106 c 1.6683,0 3.01119,-0.24778 3.01119,-0.55552 0,-0.30774 -1.34289,-0.55552 -3.01119,-0.55552 H 65.83028 A 4.0588107,4.0588107 0 0 0 65.51867,68.54304 4.0588107,4.0588107 0 0 0 62.31628,66.1344 v -7.63157 h 26.281596 c 1.57959,0 2.85099,-1.27192 2.85099,-2.85151 v -8.27753 c 0,-1.57958 -1.2714,-2.85099 -2.85099,-2.85099 H 62.31628 v -3.575495 h 26.281596 c 1.57959,0 2.85099,-1.27192 2.85099,-2.851506 v -8.277531 c 0,-1.579585 -1.2714,-2.850989 -2.85099,-2.850989 H 62.31628 v -3.891752 h 26.281596 c 1.57959,0 2.85099,-1.271921 2.85099,-2.851506 V 11.94646 c 0,-1.579584 -1.2714,-2.8509877 -2.85099,-2.8509877 z"
inkscape:label="FNS" />
<g
id="g13"
inkscape:label="two arrows">
<path
style="fill:#ffffff;stroke:#000000;stroke-width:1.5;stroke-dasharray:none;marker-start:url(#ArrowWide)"
d="m 100.17269,112.57855 25.9227,-13.146507 z"
id="path10" />
<path
style="fill:#ffffff;stroke:#000000;stroke-width:1.5;stroke-dasharray:none;marker-end:url(#marker13)"
d="m 128.92299,105.88982 -25.9227,13.14651 z"
id="path10-5" />
</g>
<text
xml:space="preserve"
style="font-size:13.7103px;text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#000000;stroke:none;stroke-width:1;stroke-dasharray:none;fill-opacity:1"
x="144.47009"
y="86.974228"
id="text10"><tspan
sodipodi:role="line"
id="tspan10"
style="stroke-width:1;stroke-dasharray:none;stroke:none;fill:#000000;fill-opacity:1"
x="144.47009"
y="86.974228">ofd.ru</tspan></text>
<text
xml:space="preserve"
style="font-size:13.3232px;text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#000000;stroke:none;stroke-width:1;stroke-dasharray:none;fill-opacity:1"
x="46.742268"
y="38.150463"
id="text11"><tspan
sodipodi:role="line"
id="tspan11"
style="stroke-width:1;stroke-dasharray:none;stroke:none;fill:#000000;fill-opacity:1"
x="46.742268"
y="38.150463">ФНС</tspan></text>
<g
id="g15"
inkscape:label="two arrows"
transform="rotate(45.923414,168.3245,81.037241)">
<path
style="fill:#ffffff;stroke:#000000;stroke-width:1.5;stroke-dasharray:none;marker-start:url(#ArrowWide)"
d="m 100.17269,112.57855 25.9227,-13.146507 z"
id="path14" />
<path
style="fill:#ffffff;stroke:#000000;stroke-width:1.5;stroke-dasharray:none;marker-end:url(#marker13)"
d="m 128.92299,105.88982 -25.9227,13.14651 z"
id="path15" />
</g>
<text
xml:space="preserve"
style="font-size:11.8523px;text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#000000;stroke:none;stroke-width:1;stroke-dasharray:none;fill-opacity:1"
x="18.578594"
y="144.58119"
id="text15"><tspan
sodipodi:role="line"
id="tspan15"
style="stroke-width:1;stroke-dasharray:none;fill:#000000;fill-opacity:1;stroke:none"
x="18.578594"
y="144.58119">Checks parser</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.7 KiB

285
assets/icons/email-text.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 138 KiB

After

Width:  |  Height:  |  Size: 138 KiB

View File

Before

Width:  |  Height:  |  Size: 649 KiB

After

Width:  |  Height:  |  Size: 649 KiB

78
assets/icons/settings.svg Normal file
View File

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="115.83108mm"
height="115.8316mm"
viewBox="0 0 115.83108 115.8316"
version="1.1"
id="svg1"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
sodipodi:docname="settings.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="true"
inkscape:zoom="0.67565763"
inkscape:cx="-76.962055"
inkscape:cy="230.88617"
inkscape:window-width="1920"
inkscape:window-height="1029"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="layer1">
<inkscape:grid
id="grid4"
units="mm"
originx="-47.084513"
originy="-90.584188"
spacingx="0.99999998"
spacingy="1"
empcolor="#0099e5"
empopacity="0.30196078"
color="#0099e5"
opacity="0.14901961"
empspacing="5"
enabled="true"
visible="true" />
</sodipodi:namedview>
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-47.084512,-90.584183)">
<rect
style="display:none;fill:#37f500;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-opacity:0.075573"
id="rect11"
width="169.95171"
height="169.95171"
x="20.362879"
y="61.871819"
ry="8.590621" />
<path
id="path10"
style="display:inline;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-opacity:0.075573"
inkscape:label="gear"
d="m 75.96901,0.80545601 c -11.155773,5e-7 -3.381873,12.02630099 -10.5755,17.65980599 2.26264,2.865218 2.781879,6.635337 1.536071,9.912568 l 0.842199,0.8422 a 23.648779,23.648779 0 0 1 8.720476,-1.56428 23.648779,23.648779 0 0 1 21.188309,14.268711 23.648779,23.648779 0 0 1 0.433613,17.637966 l 8.483422,8.483422 c 0.001,-1.137526 0.23505,-2.370832 0.79807,-3.730066 4.67012,-11.27469 19.06665,-0.813378 19.06665,-13.017015 0,-12.203637 -14.39653,-1.742323 -19.06665,-13.017014 -4.67013,-11.27469 12.9067,-14.057796 4.27742,-22.68707 -8.62927,-8.6292737 -11.41192,8.948014 -22.686611,4.277884 C 77.711789,15.202439 88.172646,0.80545546 75.96901,0.80545601 Z M 106.5976,68.045849 c -0.009,8.298119 12.66446,11.368041 5.07549,18.957003 -7.59196,7.591964 -10.66109,-5.094535 -18.966554,-5.075493 l 16.355784,16.355783 c 2.70707,2.707048 7.06538,2.707048 9.77243,0 l 4.11408,-4.114084 c 2.70705,-2.707068 2.70705,-7.065327 0,-9.77243 z M 92.706536,81.927359 84.164419,73.385241 A 23.648779,23.648779 0 0 1 54.292034,60.751335 l -0.0678,-0.156519 A 23.648779,23.648779 0 0 1 53.850687,43.071964 l -0.808075,-0.808075 c -3.276856,1.245655 -7.046115,0.726779 -9.911204,-1.53516 -5.635193,7.18452 -17.655256,-0.582996 -17.655256,10.570039 1e-6,12.203638 14.396527,1.742324 19.066657,13.017015 4.67013,11.274689 -12.907157,14.057795 -4.277883,22.687069 8.629275,8.629275 11.412378,-8.948013 22.687069,-4.277883 11.27469,4.670129 0.813378,19.067111 13.017015,19.067111 12.203637,0 1.742778,-14.396981 13.017469,-19.067111 1.355311,-0.561389 2.58526,-0.795009 3.720057,-0.79761 z M 43.131408,40.728729 c 0.530828,-0.676772 1.009354,-1.476346 1.411401,-2.446975 1.382806,-3.338388 0.796238,-5.922366 -0.464097,-8.143995 -5.610754,-0.603322 -9.948354,-8.65044 -17.091514,-10.361651 -0.190642,2.831294 0.790952,5.725383 2.964307,7.898752 l 12.263539,12.263539 c 0.290197,0.290195 0.602358,0.542427 0.916364,0.79033 z m 0.947304,-10.59097 c 2.166221,0.232933 4.522048,-0.640922 7.302705,-3.421578 2.784135,-2.78414 3.656675,-5.142371 3.420669,-7.310895 -5.277946,-2.997957 -8.46522,-9.8825424 -14.53716,-3.810602 -6.074184,6.074185 0.81761,9.261629 3.813786,14.543075 z M 54.802086,19.405286 c 2.222924,1.262656 4.808593,1.851301 8.149909,0.467282 0.968102,-0.401001 1.765816,-0.878149 2.441515,-1.407306 -0.247687,-0.313651 -0.499528,-0.625564 -0.78942,-0.915455 L 52.340551,5.2862683 C 50.34246,3.2881697 47.734568,2.2888648 45.127026,2.2887468 v 4.55e-4 c -0.228937,-1.05e-5 -0.457614,0.017002 -0.686136,0.032305 1.710334,7.1397402 9.75097,11.4767772 10.361196,17.0837792 z M 53.850687,43.071964 84.164419,73.385241 A 23.648779,23.648779 0 0 0 85.382901,72.993034 23.648779,23.648779 0 0 0 98.114178,59.562427 L 67.77178,29.22003 a 23.648779,23.648779 0 0 0 -1.137947,0.350348 23.648779,23.648779 0 0 0 -12.783146,13.501586 z"
transform="matrix(1.1357528,0,0,1.1357528,18.717777,90.23726)" />
<path
id="path11"
style="display:none;fill:#f50000;fill-opacity:1;stroke:#000000;stroke-width:1.51285;stroke-opacity:0.075573"
d="m 63.089959,81.902523 c -0.311091,-1.7e-5 -0.621755,0.02326 -0.932283,0.04412 3.222959,13.454148 22.996087,19.583657 9.430752,33.149007 -13.565319,13.56532 -19.694039,-6.20771 -33.148136,-9.43075 -0.259055,3.84733 1.074576,7.78001 4.02786,10.73331 l 16.664641,16.66466 c 3.992393,3.99236 9.772658,5.03826 14.71346,3.16006 l 76.122907,76.12203 c 3.67851,3.67851 9.60071,3.67851 13.27922,0 l 5.59023,-5.59023 c 3.6785,-3.67853 3.6785,-9.60066 0,-13.27923 L 92.71658,117.35349 c 1.878195,-4.9408 0.832348,-10.72105 -3.16008,-14.71346 L 72.891859,85.975392 c -2.715126,-2.715126 -6.258615,-4.072783 -9.8019,-4.072937 z"
inkscape:label="wrench" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@ -0,0 +1,219 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="182.87955mm"
height="144.54501mm"
viewBox="0 0 182.87955 144.54501"
version="1.1"
id="svg1"
xml:space="preserve"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
sodipodi:docname="using_binary_eye.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="0.5052024"
inkscape:cx="555.22302"
inkscape:cy="211.7963"
inkscape:window-width="1920"
inkscape:window-height="1029"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="g3" /><defs
id="defs1"><marker
style="overflow:visible"
id="ArrowWide"
refX="0"
refY="0"
orient="auto-start-reverse"
inkscape:stockid="Wide arrow"
markerWidth="1"
markerHeight="1"
viewBox="0 0 1 1"
inkscape:isstock="true"
inkscape:collect="always"
preserveAspectRatio="xMidYMid"><path
style="fill:none;stroke:context-stroke;stroke-width:1;stroke-linecap:butt"
d="M 3,-3 0,0 3,3"
transform="rotate(180,0.125,0)"
sodipodi:nodetypes="ccc"
id="path1" /></marker><marker
style="overflow:visible"
id="marker13"
refX="0"
refY="0"
orient="auto-start-reverse"
inkscape:stockid="Wide arrow"
markerWidth="1"
markerHeight="1"
viewBox="0 0 1 1"
inkscape:isstock="true"
inkscape:collect="always"
preserveAspectRatio="xMidYMid"><path
style="fill:none;stroke:context-stroke;stroke-width:1;stroke-linecap:butt"
d="M 3,-3 0,0 3,3"
transform="rotate(180,0.125,0)"
sodipodi:nodetypes="ccc"
id="path13" /></marker></defs><g
inkscape:label="Phone"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-25.853363,-48.893891)"><rect
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-opacity:1"
id="rect1"
width="57.029922"
height="97.02494"
x="26.353363"
y="95.913963"
rx="7.7330093"
ry="7.3138995"
inkscape:label="border" /><g
id="g1837"
inkscape:label="binary eye logo"
transform="translate(-69.392567,-90.079408)"><circle
r="23.283333"
cy="234.73807"
cx="123.78944"
id="circle-1"
style="fill:#a6c45f;fill-opacity:1;stroke:none;stroke-width:1.05833;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /><circle
style="fill:#b6d46f;fill-opacity:1;stroke:none;stroke-width:1.05833;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="circle-2"
cx="123.78944"
cy="234.20889"
r="23.283333" /><path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:0.12549;fill-rule:nonzero;stroke:none;stroke-width:2.27733;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 124.32389,217.397 c -4.43071,0 -8.86142,1.68857 -12.2391,5.06624 -6.7556,6.75587 -6.7556,17.72311 0,24.47872 l 10.48915,10.48941 c 0.40454,0.0307 0.80989,0.0511 1.21549,0.0609 12.85901,0 23.28333,-10.42432 23.28333,-23.28333 -0.003,-0.42731 -0.0185,-0.85461 -0.0455,-1.28112 l -10.46453,-10.46453 c -3.37767,-3.37767 -7.80838,-5.06624 -12.23883,-5.06624 z"
id="path-1" /><circle
r="17.155054"
cy="234.55074"
cx="124.12916"
id="circle-3"
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.05833;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /><path
d="m 136.31216,234.55073 c 0,2.98132 -1.07077,5.71262 -2.84903,7.83008 v -15.66016 c 1.77826,2.11746 2.84903,4.84875 2.84903,7.83008 z m -12.183,12.183 c -0.34925,0 -0.69506,-0.0148 -1.0369,-0.0434 v -24.27922 c 0.34184,-0.0286 0.68765,-0.0434 1.0369,-0.0434 0.34925,0 0.69506,0.0148 1.0369,0.0434 v 24.27922 c -0.34184,0.0286 -0.68765,0.0434 -1.0369,0.0434 z m -12.18301,-12.183 c 0,-2.98133 1.07077,-5.71262 2.84904,-7.83008 v 15.66016 c -1.77827,-2.11746 -2.84904,-4.84876 -2.84904,-7.83008 z m 17.36858,11.02757 c -0.6612,0.31141 -1.35494,0.56515 -2.0746,0.75459 v -23.56432 c 0.71966,0.18944 1.4134,0.44317 2.0746,0.75459 z m -8.29707,0.75459 c -1.51898,-0.40005 -2.92206,-1.08612 -4.14788,-1.99708 v -19.57017 c 1.22582,-0.91096 2.6289,-1.59702 4.14788,-1.99707 z"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.05833;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="circle-6" /></g></g><g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="QR code"
transform="translate(-30.254583,-85.236427)"><rect
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-opacity:1"
id="rect1837"
width="14.072319"
height="14.072319"
x="42.246078"
y="85.736427"
rx="0"
ry="0" /><rect
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.484034;stroke-opacity:1"
id="rect1838"
width="6.8114772"
height="6.8114772"
x="45.876503"
y="89.366852"
rx="0"
ry="0" /><rect
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-opacity:1"
id="rect1839"
width="14.072319"
height="14.072319"
x="62.243584"
y="85.736427"
rx="0"
ry="0" /><rect
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.484034;stroke-opacity:1"
id="rect1840"
width="6.8114772"
height="6.8114772"
x="65.874008"
y="89.366852"
rx="0"
ry="0" /><rect
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-opacity:1"
id="rect1841"
width="14.072319"
height="14.072319"
x="42.246078"
y="105.54877"
rx="0"
ry="0" /><rect
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.484034;stroke-opacity:1"
id="rect1842"
width="6.8114772"
height="6.8114772"
x="45.876503"
y="109.17919"
rx="0"
ry="0" /><rect
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.484034;stroke-opacity:1"
id="rect1844"
width="6.8114772"
height="6.8114772"
x="61.846733"
y="105.52224"
rx="0"
ry="0" /><rect
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.484034;stroke-opacity:1"
id="rect1845"
width="6.8114772"
height="6.8114772"
x="69.130707"
y="112.81159"
rx="0"
ry="0" /><g
id="g3"
inkscape:label="laptop"
transform="translate(82.762838,125.57409)"><rect
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:4;stroke-dasharray:none;stroke-opacity:1"
id="rect1-6"
width="83.00206"
height="51.927536"
x="43.381889"
y="35.094681"
ry="2.8804462" /><rect
style="fill:#ffffff;stroke:#000000;stroke-width:4;stroke-dasharray:none"
id="rect2"
width="85.730049"
height="4.8142142"
x="42.641239"
y="93.605896"
ry="2.4071071" /><rect
style="fill:#ffffff;stroke:#000000;stroke-width:0;stroke-dasharray:none"
id="rect3"
width="8.389514"
height="1.2071242"
x="81.12114"
y="86.429092"
ry="0.60356212" /><g
id="g1"
transform="translate(27.69601,-81.170421)"><text
xml:space="preserve"
style="font-size:11.8523px;text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-dasharray:none"
x="18.578594"
y="144.58119"
id="text15"><tspan
sodipodi:role="line"
id="tspan15"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-dasharray:none"
x="18.578594"
y="144.58119">Checks parser</tspan></text></g><g
id="g13"
inkscape:label="two arrows"
transform="rotate(30,151.73824,-82.354999)"><path
style="fill:#ffffff;stroke:#000000;stroke-width:1.5;stroke-dasharray:none;marker-start:url(#ArrowWide)"
d="m 100.17269,112.57855 25.9227,-13.146507 z"
id="path10" /><path
style="fill:#ffffff;stroke:#000000;stroke-width:1.5;stroke-dasharray:none;marker-end:url(#marker13)"
d="m 128.92299,105.88982 -25.9227,13.14651 z"
id="path10-5" /></g></g></g></svg>

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

@ -5,10 +5,16 @@ Check::Check() {}
void Check::add_goods(Goods goods) { this->goods.push_back(goods); } void Check::add_goods(Goods goods) { this->goods.push_back(goods); }
void Check::add_goods(std::vector<Goods> &goods) {
for (auto g : goods) {
this->goods.push_back(g);
}
}
double Check::calculae_total_price() { double Check::calculae_total_price() {
double total = 0.0; double total = 0.0;
for (Goods g : this->goods) { for (Goods &g : goods) {
total += g.calculate_total_price(); total += g.calculate_total_price();
} }

View File

@ -9,6 +9,7 @@ class Check {
public: public:
Check(); Check();
void add_goods(Goods); void add_goods(Goods);
void add_goods(std::vector<Goods> &goods);
double calculae_total_price(); double calculae_total_price();

View File

@ -1,34 +0,0 @@
FROM archlinux
#Update
RUN pacman --noconfirm -Sy
#Build dependencies
RUN pacman --noconfirm -S sudo cmake git coreutils base-devel qt5-base
RUN echo "MAKEFLAGS=\"-j${nproc}\"" >> /etc/makepkg.conf
RUN useradd -ms /bin/bash checks-parser
RUN usermod -a -G wheel checks-parser
RUN echo "checks-parser ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
USER checks-parser
WORKDIR /home/checks-parser
#Dependencies from sources
RUN git clone https://aur.archlinux.org/yay.git && \
cd yay && \
makepkg -si --noconfirm && \
cd .. && sudo rm -rf yay
RUN yay -S opencv zbar nlohmann-json tesseract tesseract-data-rus
#building
WORKDIR /home/checks-parser
RUN git clone https://git.foxarmy.org/leca/checks-parser && \
cd checks-parser && \
cmake . && \
make -j ${nproc} && \
sudo make install
ENTRYPOINT ["checks-parser"]

View File

@ -1,34 +0,0 @@
FROM debian:bullseye
#Update
RUN apt update -y && apt upgrade -y
#Build dependencies
RUN apt install -y git build-essential cmake
#Dependencies from repos (qt5, openssl, tesseract and lang package)
RUN apt install -y qtbase5-dev openssl libmbedtls-dev tesseract-ocr tesseract-ocr-rus libopencv-dev
#Dependencies from sources
#cpr
WORKDIR /root
RUN git clone https://github.com/whoshuu/cpr.git && \
cd cpr && \
mkdir build && cd build && \
cmake .. && \
make -j ${nproc} && \
make install && \
cd /root && rm -rf cpr
#building
WORKDIR /root
RUN git clone https://git.foxarmy.org/leca/checks-parser && \
cd checks-parser && \
mkdir build && cd build &&\
cmake .. && \
make -j ${nproc} && \
make install && \
ENTRYPOINT ["checks-parser"]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

View File

@ -1,4 +1,5 @@
#!/bin/bash #!/bin/bash
export TESSDATA_PREFIX=$APPDIR/usr/share/tesseract-ocr/4.00/tessdata export TESSDATA_PREFIX=$APPDIR/usr/share/tesseract-ocr/4.00/tessdata
export LD_LIBRARY_PATH=$APPDIR/usr/lib
$APPDIR/usr/bin/checks-parser $APPDIR/usr/bin/checks-parser

View File

@ -0,0 +1,31 @@
FROM checks_parser_base_ubuntu
RUN DEBIAN_FRONTEND=noninteractive apt update
RUN DEBIAN_FRONTEND=noninteractive apt install -y wget git cmake make gcc g++ fuse libboost-regex-dev
ARG pkgname=$name
ARG pkgver=$version
ARG revision
WORKDIR /
# Download linuxdeployqt
RUN wget https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage -O /usr/bin/linuxdeployqt && \
chmod +x /usr/bin/linuxdeployqt
# Prepare AppDir and its files
WORKDIR /app
RUN mkdir -p AppDir/usr/bin
COPY deploy/appimage/checks-parser.desktop AppDir
COPY assets/icons/icon.png AppDir/checks-parser.png
COPY deploy/appimage/AppRun AppDir
RUN chmod +x AppDir/AppRun
RUN cp build/checks-parser /app/AppDir/usr/bin
RUN PATH=/usr/lib/qt5/bin/:$PATH linuxdeployqt --appimage-extract-and-run AppDir/usr/bin/checks-parser -no-copy-copyright-files -appimage
RUN mkdir -p /output
RUN echo "cp Checks_parser-x86_64.AppImage /output/Checks_parser-x86_64_${pkgver}-${revision}.AppImage" > /deploy.sh
RUN chmod +x /deploy.sh
ENTRYPOINT ["bash", "/deploy.sh"]

View File

@ -1,31 +0,0 @@
#!/usr/bin/env bash
rm -rf AppDir
mkdir -p AppDir
mkdir -p AppDir/usr/bin
mkdir -p AppDir/usr/lib
mkdir -p AppDir/usr/share/tesseract-ocr/4.00/tessdata
cp -r /usr/share/tesseract-ocr/4.00/tessdata/* AppDir/usr/share/tesseract-ocr/4.00/tessdata
cp ../../checks-parser AppDir/usr/bin
echo \
"[Desktop Entry]
Name=Checks parser
Exec=usr/bin/checks-parser
Icon=checks-parser
Type=Application
Categories=Utility;" \
> AppDir/checks-parser.desktop
echo \
"#!/bin/bash
export TESSDATA_PREFIX=\$APPDIR/usr/share/tesseract-ocr/4.00/tessdata
\$APPDIR/usr/bin/checks-parser" \
> AppDir/AppRun
cp ../../icon.png AppDir/checks-parser.png
chmod +x AppDir/AppRun
cp ../../checks-parser AppDir/usr/bin
linuxdeployqt AppDir/usr/bin/checks-parser -no-copy-copyright-files -appimage

View File

@ -0,0 +1,28 @@
FROM archlinux:latest
ARG pkgname=$name
ARG pkgver=$version
ARG revision
RUN mkdir -p /output
RUN pacman --noconfirm -Syu base base-devel sudo
RUN echo "sudo cp ${pkgname}-bin-${pkgver}-$revision-x86_64.pkg.tar.zst /output" > /deploy.sh
RUN chmod +x /deploy.sh
RUN useradd -m builder
RUN usermod -a -G wheel builder
RUN chown -R builder:builder /output
RUN echo "%wheel ALL=(ALL:ALL) NOPASSWD: ALL" > /etc/sudoers
USER builder
WORKDIR /home/builder/checks-parser
COPY deploy/archlinux/bin/PKGBUILD PKGBUILD
RUN sed -i "s|\$pkgname|${pkgname}-bin|g" PKGBUILD
RUN sed -i "s|\$pkgver|${pkgver}|g" PKGBUILD
RUN sed -i "s|\$pkgrel|$revision|g" PKGBUILD
RUN makepkg -s --noconfirm
#ENTRYPOINT ["bash"]
ENTRYPOINT ["bash", "/deploy.sh"]

View File

@ -0,0 +1,40 @@
# Maintainer: Leca <leca@foxarmy.org>
pkgname=$pkgname
pkgver=$pkgver
pkgrel=$pkgrel
epoch=
pkgdesc="Utility for parsing checks(receipts) to csv"
arch=('x86_64')
url="https://git.foxarmy.org/leca/checks-parser"
license=('GPL-3.0-or-later')
groups=()
depends=('qt5-base' 'opencv' 'zbar' 'nlohmann-json' 'tesseract' 'qrencode' 'boost')
makedepends=('cmake' 'make' 'gcc' 'git' 'qt5-tools')
checkdepends=()
optdepends=('tesseract-data-rus: scan russian checks with OCR')
provides=()
conflicts=("checks-parser-git")
replaces=()
backup=()
options=()
install=
changelog=
_releasesurl=https://git.foxarmy.org/leca/checks-parser/releases/download/$pkgver
source=("checks-parser-bin::https+$releaseurl/checks-parser-git-${pkgver}_nightly-$pkgrel-x86_64.pkg.tar.zst")
noextract=()
sha256sums=('SKIP')
build() {
cd "$pkgname"
mkdir build && cd build
cmake -DBUILD_TRANSLATIONS=on ..
make -j ${nproc}
}
package() {
cd "$pkgname"
cd build
install -Dm644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
##install -Dm755
make DESTDIR="$pkgdir/" PREFIX="/usr" install
}

View File

@ -0,0 +1,28 @@
FROM archlinux:latest
ARG pkgname=$name
ARG pkgver=$version
ARG revision
RUN mkdir -p /output
RUN pacman --noconfirm -Syu base base-devel sudo
RUN echo "sudo cp ${pkgname}-git-${pkgver}_nightly-$revision-x86_64.pkg.tar.zst /output" > /deploy.sh
RUN chmod +x /deploy.sh
RUN useradd -m builder
RUN usermod -a -G wheel builder
RUN chown -R builder:builder /output
RUN echo "%wheel ALL=(ALL:ALL) NOPASSWD: ALL" > /etc/sudoers
USER builder
WORKDIR /home/builder/checks-parser
COPY deploy/archlinux/git/PKGBUILD PKGBUILD
RUN sed -i "s|\$pkgname|${pkgname}-git|g" PKGBUILD
RUN sed -i "s|\$pkgver|${pkgver}_nightly|g" PKGBUILD
RUN sed -i "s|\$pkgrel|$revision|g" PKGBUILD
RUN makepkg -s --noconfirm
#ENTRYPOINT ["bash"]
ENTRYPOINT ["bash", "/deploy.sh"]

View File

@ -1,19 +1,19 @@
# Maintainer: Leca <leca@foxarmy.org> # Maintainer: Leca <leca@foxarmy.org>
pkgname=checks-parser-git pkgname=$pkgname
pkgver=alpha_0.0.2 pkgver=$pkgver
pkgrel=1 pkgrel=$pkgrel
epoch= epoch=
pkgdesc="Utility for parsing checks(receipts) to csv" pkgdesc="Utility for parsing checks(receipts) to csv"
arch=('x86_64') arch=('x86_64')
url="https://git.foxarmy.org/leca/checks-parser" url="https://git.foxarmy.org/leca/checks-parser"
license=('GPL-3.0-or-later') license=('GPL-3.0-or-later')
groups=() groups=()
depends=('qt5-base' 'opencv' 'zbar' 'nlohmann-json' 'tesseract') depends=('qt5-base' 'opencv' 'zbar' 'nlohmann-json' 'tesseract' 'qrencode' 'boost')
makedepends=('cmake' 'make' 'gcc' 'git' 'qt5-tools') makedepends=('cmake' 'make' 'gcc' 'git' 'qt5-tools')
checkdepends=() checkdepends=()
optdepends=('tesseract-data-rus: scan russian checks with OCR') optdepends=('tesseract-data-rus: scan russian checks with OCR')
provides=() provides=()
conflicts=() conflicts=("checks-parser-bin")
replaces=() replaces=()
backup=() backup=()
options=() options=()
@ -25,7 +25,7 @@ sha256sums=('SKIP')
build() { build() {
cd "$pkgname" cd "$pkgname"
cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr . cmake -DBUILD_TRANSLATIONS=on .
make -j ${nproc} make -j ${nproc}
} }

View File

@ -0,0 +1,31 @@
FROM ubuntu:18.04
# Installing dependencies
RUN apt update
RUN DEBIAN_FRONTEND=noninteractive apt install -y qtbase5-dev openssl libmbedtls-dev libopencv-dev libzbar-dev qttools5-dev nlohmann-json-dev libcurl4-openssl-dev libqrencode-dev
RUN DEBIAN_FRONTEND=noninteractive apt install -y wget git cmake make gcc g++ fuse libboost-regex-dev
WORKDIR /app
#Copy only necessities
COPY assets ./assets
COPY check ./check
COPY exceptions ./exceptions
COPY goods ./goods
COPY image_redactor ./image_redactor
COPY output ./output
COPY settings ./settings
COPY scenes ./scenes
COPY net ./net
COPY translations ./translations
COPY http_server ./http_server
COPY utils ./utils
COPY ./*.h ./*cpp ./*.ui ./*.qrc CMakeLists.txt .
WORKDIR /app/build
RUN cmake -DBUILD_TRANSLATIONS=on .. && make -j 8
ENTRYPOINT ["bash"]

29
deploy/debian/Dockerfile Normal file
View File

@ -0,0 +1,29 @@
FROM checks_parser_base_ubuntu
#for envsubst
RUN DEBIAN_FRONTEND=noninteractive apt install -y gettext
ARG pkgname=$name
ARG pkgver=$version
ARG revision
ARG pkg=${pkgname}_$pkgver-$revision
WORKDIR /app
RUN mkdir -p $pkg/DEBIAN
RUN mkdir -p $pkg/usr/bin
RUN mkdir -p /output
COPY deploy/debian/control $pkg/DEBIAN/control
COPY deploy/debian/copy.sh .
RUN envsubst < $pkg/DEBIAN/control | tee $pkg/DEBIAN/control.output && mv $pkg/DEBIAN/control.output $pkg/DEBIAN/control
RUN envsubst < copy.sh | tee copy.sh.output && mv copy.sh.output copy.sh
RUN chmod +x copy.sh
RUN cp /app/build/checks-parser $pkg/usr/bin
RUN dpkg-deb --build $pkg
ENTRYPOINT ["./copy.sh"]

10
deploy/debian/control Normal file
View File

@ -0,0 +1,10 @@
Package: checks-parser
Version: 3.0-1
Section: utils
Priority: optional
Architecture: amd64
Homepage: https://git.foxarmy.org/checks-parser
Depends: libc, qtbase5-dev, openssl, libmbedtls-dev, tesseract-ocr, tesseract-ocr-rus, libopencv-dev, libzbar-dev, qttools5-dev, nlohmann-json3-dev, libcurl4-openssl-dev, libtesseract-dev, libqrencode-dev
Maintainer: Leca <leca@foxarmy.org>
Description: Utility for parsing checks(receipts) to csv
Utility for extraction of content of a check(receipt) using plaintext, OCR or request to FTS (Federal Taxation Service)

2
deploy/debian/copy.sh Normal file
View File

@ -0,0 +1,2 @@
#!/usr/bin/env bash
cp $pkg.deb /output

View File

@ -1,30 +0,0 @@
#!/usr/bin/env bash
pkgname="checks-parser"
pkgver="3.0"
revision="1"
pkg=${pkgname}_$pkgver-$revision
mkdir $pkg
mkdir -p $pkg/usr/bin
cp ../../checks-parser $pkg/usr/bin
mkdir $pkg/DEBIAN
echo \
"Package: $pkgname
Version: $pkgver-$revision
Section: utils
Priority: optional
Architecture: amd64
Homepage: https://git.foxarmy.org/checks-parser
Depends: libc, qtbase5-dev, openssl, libmbedtls-dev, tesseract-ocr, tesseract-ocr-rus, libopencv-dev, libzbar-dev, qttools5-dev, nlohmann-json3-dev, libcurl4-openssl-dev, libtesseract-dev
Maintainer: Leca <leca@foxarmy.org>
Description: Utility for parsing checks(receipts) to csv
Utility for extraction of content of a check(receipt) using plaintext, OCR or request to FTS (Federal Taxation Service)"\
> $pkg/DEBIAN/control
dpkg-deb --build $pkg
rm -rf $pkg

View File

@ -0,0 +1,9 @@
FROM checks_parser_base_ubuntu
RUN DEBIAN_FRONTEND=noninteractive apt install -y autoconf automake autopoint bash bison bzip2 flex g++ g++-multilib gettext git gperf intltool libc6-dev-i386 libgdk-pixbuf2.0-dev libltdl-dev libgl-dev libpcre3-dev libssl-dev libtool-bin libxml-parser-perl lzip make openssl p7zip-full patch perl python3 python3-distutils python3-mako python3-packaging python3-pkg-resources python3-setuptools python-is-python3 ruby sed sqlite3 unzip wget xz-utils
WORKDIR /
RUN git clone https://github.com/mxe/mxe.git
RUN cd mxe && make qt

46
docker-compose.yml Normal file
View File

@ -0,0 +1,46 @@
services:
base_ubuntu:
image: checks_parser_base_ubuntu:latest
build:
context: .
dockerfile: deploy/base-docker/ubuntu/Dockerfile
appimage:
image: checks_parser_appimage:latest
env_file: .env
build:
dockerfile: deploy/appimage/Dockerfile
context: .
args:
- pkgname=$name
- pkgver=$version
- revision=$revision
volumes:
- ./binaries:/output
depends_on:
- base_ubuntu
debian:
image: checks_parser_debian:latest
env_file: .env
build:
dockerfile: deploy/debian/Dockerfile
context: .
args:
- pkgname=$name
- pkgver=$version
- revision=$revision
volumes:
- ./binaries:/output
depends_on:
- base_ubuntu
archlinux:
image: checks_parser_base_arch:latest
env_file: .env
build:
dockerfile: deploy/archlinux/git/Dockerfile
context: .
args:
- pkgname=$name
- pkgver=$version
- revision=$revision
volumes:
- ./binaries:/output

View File

@ -1,11 +1,9 @@
#include "goods.h" #include "goods.h"
#include <string> #include <string>
Goods::Goods(std::string name, double price_per_unit, double quantity) { Goods::Goods(std::string name, double price_per_unit, std::string net_weight, double quantity) :
this->name = name; name(name), price_per_unit(price_per_unit),
this->price_per_unit = price_per_unit; net_weight(net_weight), quantity(quantity) {}
this->quantity = quantity;
}
double Goods::calculate_total_price() { double Goods::calculate_total_price() {
return this->price_per_unit * this->quantity; return this->price_per_unit * this->quantity;
@ -15,12 +13,16 @@ std::string Goods::get_name() { return this->name; }
double Goods::get_quantity() { return this->quantity; } double Goods::get_quantity() { return this->quantity; }
std::string Goods::get_net_weight() { return this->net_weight; }
double Goods::get_price_per_unit() { return this->price_per_unit; } double Goods::get_price_per_unit() { return this->price_per_unit; }
void Goods::set_name(std::string name) { this->name = name; } void Goods::set_name(std::string name) { this->name = name; }
void Goods::set_quantity(double quantity) { this->quantity = quantity; } void Goods::set_quantity(double quantity) { this->quantity = quantity; }
void Goods::set_net_weight(std::string net_weight) { this->net_weight = net_weight; }
void Goods::set_price_per_unit(double price_per_unit) { void Goods::set_price_per_unit(double price_per_unit) {
this->price_per_unit = price_per_unit; this->price_per_unit = price_per_unit;
} }

View File

@ -7,17 +7,20 @@ class Goods
{ {
std::string name; std::string name;
double quantity; // by weight or by the piece double quantity; // by weight or by the piece
std::string net_weight; // will contain values like "5мл" or "10г"
double price_per_unit; double price_per_unit;
public: public:
Goods(std::string, double, double); Goods(std::string name, double quantity, std::string net_weight, double price_per_unit);
double calculate_total_price(); double calculate_total_price();
std::string get_name(); std::string get_name();
double get_quantity(); double get_quantity();
std::string get_net_weight();
double get_price_per_unit(); double get_price_per_unit();
void set_name(std::string); void set_name(std::string);
void set_quantity(double); void set_quantity(double);
void set_net_weight(std::string);
void set_price_per_unit(double); void set_price_per_unit(double);
}; };

113
http_server/http_server.cpp Normal file
View File

@ -0,0 +1,113 @@
#include "http_server.h"
#include <qobjectdefs.h>
#include <unistd.h>
#include <utils/utils.h>
#include <iostream>
#include <mainwindow.h>
#include <thread>
void HttpServer::generateRandomPort() {
port = rand() % (65535 - 1024) + 1024;
}
HttpServer::HttpServer(QWidget *caller) : caller(caller) {
started = false;
port = 8080;
}
HttpServer::~HttpServer() {
started = false;
shutdown(serverSocket, SHUT_RDWR);
close(serverSocket);
for (auto &thread : clientHandlersThreads) {
thread.join();
}
listenClientsThread.join();
}
int HttpServer::start() {
unsigned short number_of_retries = 0;
while (number_of_retries < 10) {
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket < 0) {
std::cerr << QObject::tr("Could not obtain socket.").toStdString() << std::endl;
number_of_retries ++;
continue;
}
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(port);
serverAddress.sin_addr.s_addr = INADDR_ANY;
if (bind(serverSocket, (sockaddr *)&serverAddress, sizeof(serverAddress)) < 0) {
std::cerr << QObject::tr("Port ").toStdString() << port << QObject::tr(" seems to be occupied. Trying to generate another one").toStdString() << std::endl;
number_of_retries ++;
generateRandomPort();
continue;
}
if (listen(serverSocket, 1) < 0) {
std::cerr << QObject::tr("Could not listen port.").toStdString() << std::endl;
number_of_retries ++;
generateRandomPort();
continue;
}
started = true;
std::cout << QObject::tr("Listening on port: ").toStdString() << port << std::endl;
listenClientsThread = std::thread(&HttpServer::acceptClients, this);
return 0;
}
return -1;
}
void HttpServer::handleClient(int clientSocket) {
std::string localIp;
try {
localIp = get_local_ip_address();
} catch(std::exception e) {
std::cerr << e.what() << std::endl;
close(clientSocket);
return;
}
char buffer[256] = {0};
recv(clientSocket, buffer, 256, 0);
std::string response = "HTTP/1.1 301 Moved Permanently\r\n"
"Content-Length: 0\r\n"
"Keep-Alive: timeout=5, max=100\r\n"
"Location: binaryeye://scan/?ret=http://" + get_local_ip_address() + ":" + std::to_string(port) + "/?result={RESULT}\r\n"
"\r\n";
if (send(clientSocket, response.c_str(), response.length(), 0) < 0) {
std::cerr << response.c_str() << std::endl;
std::cerr << response.length() << std::endl;
std::cerr << QObject::tr("Could not send message").toStdString() << std::endl;
}
emit ((MainWindow *)caller)->httpNewMessage(QString::fromStdString(std::string(buffer)));
}
void HttpServer::acceptClients() {
while (true) {
if (!started) return;
int clientSocket = accept(serverSocket, nullptr, nullptr);
if (!started) return;
clientHandlersThreads.push_back (
std::thread(&HttpServer::handleClient, this, clientSocket)
);
}
}
unsigned short HttpServer::getPort() {
return port;
}
bool HttpServer::isStarted() {
return started;
}

37
http_server/http_server.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef CHECKS_PARSER_HTTP_SERVER
#define CHECKS_PARSER_HTTP_SERVER
#include <netinet/in.h>
#include <QWidget>
#include <thread>
#include <vector>
class HttpServer {
private:
unsigned short port;
int serverSocket;
sockaddr_in serverAddress;
QWidget* caller;
std::thread listenClientsThread;
std::vector<std::thread> clientHandlersThreads;
bool started;
void generateRandomPort();
public:
HttpServer(QWidget *caller);
~HttpServer();
int start();
void stop();
void handleClient(int clientSocket);
void acceptClients();
unsigned short getPort();
bool isStarted();
};
#endif //CHECKS_PARSER_HTTP_SERVER

View File

@ -1,23 +0,0 @@
#include <string>
#include <tesseract/baseapi.h>
#include <leptonica/allheaders.h>
#include <opencv2/opencv.hpp>
#include "checkimage.h"
CheckImage::CheckImage(std::string path) {
this->path = path;
}
std::string CheckImage::parse_text() {
std::string result;
tesseract::TessBaseAPI *ocr = new tesseract::TessBaseAPI();
ocr->Init(NULL, "rus", tesseract::OEM_LSTM_ONLY);
ocr->SetPageSegMode(tesseract::PSM_AUTO);
cv::Mat im = cv::imread(this->path, cv::IMREAD_COLOR);
ocr->SetImage(im.data, im.cols, im.rows, 3, im.step);
result = std::string(ocr->GetUTF8Text());
return result;
}

View File

@ -1,15 +0,0 @@
#ifndef CHECKIMAGE_H
#define CHECKIMAGE_H
#include <string>
class CheckImage {
std::string path;
public:
CheckImage(std::string path);
std::string parse_text();
};
#endif // CHECKIMAGE_H

View File

@ -32,8 +32,7 @@ void ImageRedactor::wheelEvent(QWheelEvent *event) {
void ImageRedactor::mousePressEvent(QMouseEvent *event) void ImageRedactor::mousePressEvent(QMouseEvent *event)
{ {
// Pan the image // Pan the image
if (event->button() == Qt::LeftButton) if (event->button() == Qt::LeftButton) {
{
setDragMode(QGraphicsView::ScrollHandDrag); setDragMode(QGraphicsView::ScrollHandDrag);
} }
} }
@ -41,8 +40,7 @@ void ImageRedactor::mousePressEvent(QMouseEvent *event)
void ImageRedactor::mouseReleaseEvent(QMouseEvent *event) void ImageRedactor::mouseReleaseEvent(QMouseEvent *event)
{ {
// Reset the drag mode // Reset the drag mode
if (event->button() == Qt::LeftButton) if (event->button() == Qt::LeftButton) {
{
setDragMode(QGraphicsView::NoDrag); setDragMode(QGraphicsView::NoDrag);
} }
} }

View File

@ -1,9 +1,11 @@
#include "mainwindow.h" #include <mainwindow.h>
#include "net/net.h" #include <net/net.h>
#include "settings/settings.h" #include <settings/settings.h>
#include "utils/utils.h" #include <utils/utils.h>
#include <QApplication> #include <QApplication>
#include <curl/curl.h> #ifdef BUILD_OFD_MODE
# include <curl/curl.h>
#endif
#include <iostream> #include <iostream>
#if __GNUC__ < 8 && __clang_major__ < 17 #if __GNUC__ < 8 && __clang_major__ < 17
# include <experimental/filesystem> # include <experimental/filesystem>
@ -12,9 +14,18 @@
# include <filesystem> # include <filesystem>
using namespace std::filesystem; using namespace std::filesystem;
#endif #endif
#include <QDateTime>
#include <QFile> #include <QFile>
#include <QStackedLayout>
#include <QTextStream> #include <QTextStream>
#include <QTranslator> #ifdef BUILD_TRANSLATIONS
# include <QTranslator>
#endif
#include <settingsdialog.h>
#ifdef BUILD_EMAIL_MODE
//placeholder
#endif
#include <QPushButton>
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
curl_global_init(CURL_GLOBAL_ALL); curl_global_init(CURL_GLOBAL_ALL);
@ -22,32 +33,23 @@ int main(int argc, char *argv[]) {
std::string program_data_path = get_path_relative_to_home(".local/share/checks_parser"); std::string program_data_path = get_path_relative_to_home(".local/share/checks_parser");
create_directories(program_data_path); create_directories(program_data_path);
srand(time(0));
QApplication app(argc, argv);
std::string settings_file_path = std::string settings_file_path =
get_path_relative_to_home(".local/share/checks_parser/settings.json"); get_path_relative_to_home(".local/share/checks_parser/settings.json");
Settings s(settings_file_path); Settings s(settings_file_path);
Net n;
Parser p;
std::vector<std::string> stores_updates = p.check_updates();
for (const std::string &update : stores_updates) {
std::cout << "Downloading "
<< s.get_setting("stores_modules_url") + update << " to "
<< get_path_relative_to_home(s.get_setting("stores_modules_dir") +
"/" + update)
<< std::endl;
n.get_file(s.get_setting("stores_modules_url") + "/" + update,
get_path_relative_to_home(s.get_setting("stores_modules_dir") +
"/" + update));
}
QApplication a(argc, argv);
#ifdef BUILD_TRANSLATIONS
QTranslator translator; QTranslator translator;
QString lang = "en_US"; QString lang = "en_US";
if (s.get_all_settings().contains("language")) { bool languageSettingPresent = false;
languageSettingPresent = s.get_all_settings().find("language") != s.get_all_settings().end();
if (languageSettingPresent) {
lang = QString::fromStdString(s.get_all_settings()["language"]); lang = QString::fromStdString(s.get_all_settings()["language"]);
} else if (translator.load(":/translation/"+QLocale::system().name()+".qm")) { } else if (translator.load(":/translation/"+QLocale::system().name()+".qm")) {
lang = QLocale::system().name(); lang = QLocale::system().name();
@ -55,14 +57,23 @@ int main(int argc, char *argv[]) {
lang = QString::fromStdString("en_US"); lang = QString::fromStdString("en_US");
} }
std::cout << "Using locale: " << lang.toStdString() << std::endl; std::cout << QObject::tr("Using locale: ").toStdString() << lang.toStdString() << std::endl;
translator.load(":/translation/" + lang + ".qm"); translator.load(":/translation/" + lang + ".qm");
app.installTranslator(&translator);
a.installTranslator(&translator); #endif
MainWindow w; MainWindow w;
w.update();
w.show(); w.show();
return a.exec(); // TODO: move to the window
//Settings button setup
// QPushButton *settingsButton = w.findChild<QPushButton *>("settings_button");
// QObject::connect(settingsButton, &QPushButton::clicked, [&]() {
// SettingsDialog d;
// d.show();
// d.exec();
// });
return app.exec();
} }

View File

@ -1,219 +1,238 @@
#include "mainwindow.h" #include <mainwindow.h>
#include "./ui_mainwindow.h" #include "ui_mainwindow.h"
#include "check/check.h"
#include "exceptions/ofdrequestexception.h"
#include "goods/goods.h"
#include "outputdialog.h"
#include "adjustpicturedialog.h"
#include "settingsdialog.h"
#include "solvecaptchadialog.h"
#include <QFileDialog> #include <QFileDialog>
#include <QMessageBox> #include <QMessageBox>
#include "image/checkimage.h" #include <QPixmap>
#include "utils/utils.h" #include <settingsdialog.h>
#include <opencv2/objdetect.hpp>
#include <opencv2/imgcodecs.hpp> #ifdef BUILD_OFD_LOCAL_QR_SCAN
#include <opencv2/highgui/highgui.hpp> # include <adjustpicturedialog.h>
#include <opencv2/imgproc/imgproc.hpp> #endif
#include <zbar.h>
#include <outputdialog.h>
#include <solvecaptchadialog.h>
#include <net/net.h>
#include <utils/utils.h>
#include <exceptions/ofdrequestexception.h>
#ifdef BUILD_OFD_BINARYEYE_SCAN
# include <qrencode.h>
# include <stdlib.h>
# include <unistd.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <netinet/in.h>
#endif
MainWindow::MainWindow(QWidget *parent) MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow) { : QWidget(parent)
, ui(new Ui::MainWindow) {
ui->setupUi(this); ui->setupUi(this);
this->setupStoresList(); ui->stop_server_button->hide();
#ifdef BUILD_OFD_BINARYEYE_SCAN
QObject::connect(this, &MainWindow::httpErrorOccured, this, &MainWindow::notifyHttpServerFailure);
connect(this, SIGNAL(httpNewMessage(QString)), this, SLOT(httpNewMessageHandler(QString)));
#endif
#ifndef BUILD_EMAIL_MODE
ui->parse_email_button->hide();
ui->or_label_2->hide();
#endif
#ifndef BUILD_OFD_BINARYEYE_SCAN
ui->or_label_2->hide();
ui->binary_eye_button->hide();
#endif
#ifndef BUILD_OFD_LOCAL_QR_SCAN
ui->or_label_1->hide();
ui->choose_image_button->hide();
#endif
QObject::connect(ui->settings_button, &QPushButton::clicked, [&]() {
SettingsDialog d;
d.show();
d.exec();
});
} }
MainWindow::~MainWindow() { delete ui; } #ifdef BUILD_OFD_BINARYEYE_SCAN
void MainWindow::startHttpServer() {
server = new HttpServer(this);
void MainWindow::setupStoresList() { if (server->start() < 0) {
parser = *(new Parser()); emit httpErrorOccured();
std::vector<std::string> modules_names = parser.search_modules();
for (std::string name : modules_names) {
StoreModule m(name);
std::wstring module_name = m.get_name();
QString s = QString::fromStdWString(module_name);
ui->storeType->addItem(s);
} }
} }
std::string MainWindow::makeRequestToOfd(std::string captcha) { void MainWindow::on_binary_eye_button_clicked() {
std::string checkContent = Net().fetch_check_data_from_ofdru( httpServerThread = new std::thread(&MainWindow::startHttpServer, this);
ui->fn_edit->text().toStdString(), ui->binary_eye_button->setEnabled(false);
ui->fd_edit->text().toStdString(), ui->stop_server_button->show();
ui->fi_edit->text().toStdString(),
ui->dateTimeEdit->dateTime().toString(Qt::ISODate).toStdString(),
ui->fundIncomeCombo->currentIndex() + 1,
// In the request to ofd.ru, total is in a strange format, like a string of a format where 2 last digits represent decimal part of a number.
ui->total_edit->text().toDouble() * 100,
captcha);
return checkContent; while (!server->isStarted()) {}
}
void MainWindow::on_parseButton_clicked() {
QString s;
switch (ui->tabWidget->currentIndex()) {
case 0:
s = ui->checkContent->toPlainText();
break;
case 1:
s = ui->checkContentFromImage->toPlainText();
break;
case 2:
Net().get_captcha_from_ofdru();
std::string solved_captcha = "";
bool success = true;
bool is_captcha_solved = true;
do {
SolveCaptchaDialog dialog = SolveCaptchaDialog(this, &solved_captcha);
dialog.exec();
is_captcha_solved = true;
try {
std::string check_content = makeRequestToOfd(solved_captcha);
check = parseOfdRuAnswer(check_content);
} catch(OfdRequestException e) {
success = false;
if (!strcmp(e.what(), "Incorrect captcha")) {
is_captcha_solved = false;
QMessageBox infoDialog;
infoDialog.setText(tr("Captcha was not solved correctly!"));
infoDialog.setIcon(QMessageBox::Critical);
infoDialog.setWindowTitle(tr("Captcha is incorrect"));
infoDialog.exec();
break;
} else if (!strcmp(e.what(), "Internal server error")) {
QMessageBox infoDialog;
infoDialog.setText(tr("Internal server error. Please, try again later."));
infoDialog.setIcon(QMessageBox::Critical);
infoDialog.setWindowTitle(tr("Internal server error"));
infoDialog.exec();
return;
} else if (!strcmp(e.what(), "Does not exist")) {
QMessageBox infoDialog;
infoDialog.setText(tr("Check not found. Please, ensure correctness of entered data."));
infoDialog.setIcon(QMessageBox::Critical);
infoDialog.setWindowTitle(tr("Check was not found"));
infoDialog.exec();
return;
}
}
} while (!is_captcha_solved);
if (success) {
OutputDialog d = OutputDialog(this, check);
d.exec();
}
std::string localIp;
try {
localIp = get_local_ip_address();
} catch(std::exception e) {
std::cerr << e.what() << std::endl;
return; return;
} }
std::wstring check_plaintext = s.toStdWString(); std::string connectionString = "binaryeye://scan?ret=http://" + localIp + ":" + std::to_string(server->getPort()) + "/?result={RESULT}";
parser.set_module(parser.search_modules()[0]);
std::vector<Goods> c = parser.parse(check_plaintext); generate_qr_code(connectionString);
if (c.size() == 0) { QMessageBox infoDialog = QMessageBox();
infoDialog.setText(QString::fromStdString(connectionString));
infoDialog.setIconPixmap(QPixmap(QString::fromStdString(get_path_relative_to_home(".local/share/checks_parser/binaryeye_connection.png"))).scaled(400, 400, Qt::KeepAspectRatio));
infoDialog.setWindowTitle(tr("QR code for binaryeye to connect"));
infoDialog.setButtonText(1, tr("I've scanned"));
infoDialog.exec();
}
void MainWindow::notifyHttpServerFailure() {
QMessageBox infoDialog = QMessageBox();
infoDialog.setText(tr("Could not start http server. 10 times in a row random port was occupied. Either you should run for a lottery ticket, or the problem is in the program. If the lottery ticket wasn't lucky, please, contact the developer."));
infoDialog.setIcon(QMessageBox::Warning);
infoDialog.setWindowTitle(tr("Could not start http server."));
infoDialog.exec();
}
void MainWindow::on_stop_server_button_clicked() {
delete server;
ui->stop_server_button->hide();
ui->binary_eye_button->setEnabled(true);
}
void MainWindow::httpNewMessageHandler(QString message) {
std::string parametersString = split(message.toStdString(), " ")[1];
//erase /?result= from the string
parametersString.erase(0, parametersString.find("=") + 1);
std::vector<std::string> parameters = split(parametersString, "&");
std::map<std::string, std::string> paramsMap;
for (auto &parameter : parameters) {
std::vector<std::string> values = split(parameter, "=");
paramsMap.insert(std::pair<std::string, std::string> (values[0], values[1]));
}
emit onDataDecode(paramsMap);
}
#endif //ifdef BUILD_OFD_BINARYEYE_SCAN
#ifdef BUILD_OFD_LOCAL_QR_SCAN
void MainWindow::on_choose_image_button_clicked() {
QString filename = QFileDialog::getOpenFileName();
if (filename == "") {
QMessageBox infoDialog; QMessageBox infoDialog;
infoDialog.setText(tr("An error has occured. Check was matched incorrectly. Vector sizes are different. Please, contact the developer.")); infoDialog.setText(tr("Please, select a picture where QR code that contains info about check is present"));
infoDialog.setIcon(QMessageBox::Critical); infoDialog.setIcon(QMessageBox::Critical);
infoDialog.setWindowTitle(tr("Error in parsing")); infoDialog.setWindowTitle(tr("Picture was not selected"));
infoDialog.exec(); infoDialog.exec();
return; return;
} }
for (auto& g : c) { ui->info_label->setText(tr("Selected image: ") + filename);
check.add_goods(g);
}
OutputDialog d = OutputDialog(this, check);
d.show();
d.exec();
}
void MainWindow::on_storeType_currentIndexChanged(int index) {
std::string module = parser.search_modules()[index];
parser.set_module(module);
}
void MainWindow::on_preferencesButton_clicked() {
SettingsDialog s = SettingsDialog();
s.show();
s.exec();
}
void MainWindow::on_chooseImageButton_ofd_clicked() {
QString filename = QFileDialog::getOpenFileName();
if (filename == "") {
QMessageBox infoDialog;
infoDialog.setText(tr("Please, select a picture where QR code that contains info about check is present"));
infoDialog.setIcon(QMessageBox::Critical);
infoDialog.setWindowTitle(tr("Picture was not selected"));
infoDialog.exec();
return;
}
std::string new_text = "Selected: " + filename.toStdString();
ui->pathLabel_ofd->setText(QString::fromStdString(new_text));
AdjustPictureDialog dialog = AdjustPictureDialog(this, filename.toStdString()); AdjustPictureDialog dialog = AdjustPictureDialog(this, filename.toStdString());
connect(&dialog, &AdjustPictureDialog::decodedData, this, &MainWindow::onDecodedData); connect(&dialog, &AdjustPictureDialog::decodedData, this, &MainWindow::onDataDecode);
dialog.exec(); dialog.exec();
ui->picture_ofd->setPixmap(QPixmap(filename));
ui->picture_ofd->setScaledContents(true);
} }
#endif //ifdef BUILD_OFD_LOCAL_QR_SCAN
void MainWindow::onDecodedData(std::string data) { void MainWindow::onDataDecode(std::map<std::string, std::string> data) {
std::string delimiter = "&"; ui->fn_line_edit->setText(QString::fromStdString(data["fn"]));
std::vector<std::string> dataSplit = split(data, delimiter); ui->fd_line_edit->setText(QString::fromStdString(data["i"]));
ui->fi_line_edit->setText(QString::fromStdString(data["fp"]));
std::cout << data << std::endl; QString extractedDateTime = QString::fromStdString(data["t"]);
//TODO: some QRs contain datetime in format yyyyMMddThhmmss. Perhaps there is more different formats, should write function to detect them.
ui->fn_edit->setText(QString::fromStdString(dataSplit[2]));
ui->fd_edit->setText(QString::fromStdString(dataSplit[3]));
ui->fi_edit->setText(QString::fromStdString(dataSplit[4]));
QString extractedDateTime = QString::fromStdString(split(dataSplit[0], "=")[1]);
QDateTime datetime = QDateTime::fromString(extractedDateTime, "yyyyMMddThhmm"); QDateTime datetime = QDateTime::fromString(extractedDateTime, "yyyyMMddThhmm");
ui->dateTimeEdit->setDateTime(datetime); if (datetime == QDateTime::fromString(extractedDateTime, "20000101T1200")) {
datetime = QDateTime::fromString(extractedDateTime, "yyyyMMddThhmmss");
}
ui->purchase_datetime_edit->setDateTime(datetime);
int type = std::stoi(split(dataSplit[5], "=")[1]); int type = std::stoi(data["n"]);
ui->fundIncomeCombo->setCurrentIndex(type - 1); ui->operation_type_combo_box->setCurrentIndex(type - 1);
std::string total = split(dataSplit[1], "=")[1]; std::string total = data["s"];
ui->total_edit->setText(QString::fromStdString(total)); ui->total_spin_box->setValue(std::stod(total));
} }
void MainWindow::on_chooseImageButton_ocr_clicked() void MainWindow::on_parse_button_clicked() {
{ Net net;
QString filename = QFileDialog::getOpenFileName(); net.get_captcha_from_ofdru();
if (filename == "") { std::string solved_captcha = "";
QMessageBox infoDialog; bool success = true;
infoDialog.setText(tr("Please, select a picture to scan")); bool is_captcha_solved = true;
infoDialog.setIcon(QMessageBox::Critical); Check check;
infoDialog.setWindowTitle(tr("Picture was not selected"));
infoDialog.exec();
return;
}
std::string new_text = "Selected: " + filename.toStdString();
ui->pathLabel_ocr->setText(QString::fromStdString(new_text));
CheckImage i(filename.toStdString()); do {
std::string parsed = i.parse_text(); SolveCaptchaDialog dialog = SolveCaptchaDialog(this, &solved_captcha);
dialog.exec();
is_captcha_solved = true;
ui->picture_ocr->setPixmap(QPixmap(filename)); try {
ui->picture_ocr->setScaledContents(true); std::string check_content = net.fetch_check_data_from_ofdru(
ui->checkContentFromImage->setPlainText(QString::fromStdString(parsed)); ui->fn_line_edit->text().toStdString(),
ui->fd_line_edit->text().toStdString(),
ui->fi_line_edit->text().toStdString(),
ui->purchase_datetime_edit->dateTime().toString(Qt::ISODate).toStdString(),
ui->operation_type_combo_box->currentIndex() + 1,
// In the request to ofd.ru, total is in a format with 2 last digits represent decimal part of a number.
ui->total_spin_box->text().toDouble() * 100,
solved_captcha);
check = parseOfdRuAnswer(check_content);
} catch(OfdRequestException e) {
success = false;
if (!strcmp(e.what(), "Incorrect captcha")) {
is_captcha_solved = false;
QMessageBox infoDialog;
infoDialog.setText(tr("Captcha was not solved correctly!"));
infoDialog.setIcon(QMessageBox::Critical);
infoDialog.setWindowTitle(tr("Captcha is incorrect"));
infoDialog.exec();
break;
} else if (!strcmp(e.what(), "Internal server error")) {
QMessageBox infoDialog;
infoDialog.setText(tr("Internal server error. Please, try again later."));
infoDialog.setIcon(QMessageBox::Critical);
infoDialog.setWindowTitle(tr("Internal server error"));
infoDialog.exec();
return;
} else if (!strcmp(e.what(), "Does not exist")) {
QMessageBox infoDialog;
infoDialog.setText(tr("Check not found. Please, ensure correctness of entered data."));
infoDialog.setIcon(QMessageBox::Critical);
infoDialog.setWindowTitle(tr("Check was not found"));
infoDialog.exec();
return;
}
}
} while (!is_captcha_solved);
if (success) {
OutputDialog *d = new OutputDialog(this, check);
d->exec();
delete d;
}
} }
MainWindow::~MainWindow() {
delete ui;
}

View File

@ -1,44 +1,53 @@
#ifndef MAINWINDOW_H #ifndef MAINWINDOW_H
#define MAINWINDOW_H #define MAINWINDOW_H
#include <QMainWindow> #include <QWidget>
#include <QEvent>
#include <thread>
#include "check/check.h" #include <http_server/http_server.h>
#include "parser/parser.h"
QT_BEGIN_NAMESPACE
namespace Ui { namespace Ui {
class MainWindow; class MainWindow;
} }
QT_END_NAMESPACE
class MainWindow : public QMainWindow { class MainWindow : public QWidget
{
Q_OBJECT Q_OBJECT
Check check;
Parser parser;
public: public:
MainWindow(QWidget *parent = nullptr); explicit MainWindow(QWidget *parent = nullptr);
~MainWindow(); ~MainWindow();
void setupStoresList(); #ifdef BUILD_OFD_BINARYEYE_SCAN
void startHttpServer();
#endif
Check get_check(); signals:
void onDecodedData(std::string); void httpNewMessage(QString message);
void httpErrorOccured();
std::string makeRequestToOfd(std::string captcha);
private slots: private slots:
void on_parseButton_clicked(); #ifdef BUILD_OFD_LOCAL_QR_SCAN
void on_choose_image_button_clicked();
#endif
void on_storeType_currentIndexChanged(int index); void onDataDecode(std::map<std::string, std::string>);
void on_parse_button_clicked();
void on_preferencesButton_clicked(); #ifdef BUILD_OFD_BINARYEYE_SCAN
void on_chooseImageButton_ofd_clicked(); void on_binary_eye_button_clicked();
void notifyHttpServerFailure();
void on_chooseImageButton_ocr_clicked(); void on_stop_server_button_clicked();
void httpNewMessageHandler(QString message);
#endif
private: private:
Ui::MainWindow *ui; Ui::MainWindow *ui;
#ifdef BUILD_OFD_BINARYEYE_SCAN
std::thread *httpServerThread;
HttpServer *server = NULL;
#endif
}; };
#endif // MAINWINDOW_H #endif // MAINWINDOW_H

View File

@ -1,401 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>817</width>
<height>659</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QComboBox" name="storeType">
<property name="geometry">
<rect>
<x>90</x>
<y>10</y>
<width>211</width>
<height>31</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="storeTypeLabel">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>81</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string>Store type</string>
</property>
</widget>
<widget class="QPushButton" name="parseButton">
<property name="geometry">
<rect>
<x>30</x>
<y>560</y>
<width>80</width>
<height>26</height>
</rect>
</property>
<property name="text">
<string>Parse</string>
</property>
</widget>
<widget class="QPushButton" name="preferencesButton">
<property name="geometry">
<rect>
<x>730</x>
<y>0</y>
<width>81</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string>Preferences</string>
</property>
</widget>
<widget class="QTabWidget" name="tabWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>50</y>
<width>801</width>
<height>511</height>
</rect>
</property>
<property name="currentIndex">
<number>2</number>
</property>
<widget class="QWidget" name="Text">
<attribute name="title">
<string>Text</string>
</attribute>
<widget class="QLabel" name="checkContentLabel">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>101</width>
<height>18</height>
</rect>
</property>
<property name="text">
<string>Check content</string>
</property>
</widget>
<widget class="QPlainTextEdit" name="checkContent">
<property name="geometry">
<rect>
<x>0</x>
<y>30</y>
<width>611</width>
<height>441</height>
</rect>
</property>
</widget>
</widget>
<widget class="QWidget" name="OCR">
<attribute name="title">
<string>OCR</string>
</attribute>
<widget class="QPushButton" name="chooseImageButton_ocr">
<property name="geometry">
<rect>
<x>10</x>
<y>0</y>
<width>80</width>
<height>26</height>
</rect>
</property>
<property name="text">
<string>Choose</string>
</property>
</widget>
<widget class="QPlainTextEdit" name="checkContentFromImage">
<property name="geometry">
<rect>
<x>0</x>
<y>60</y>
<width>511</width>
<height>401</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="pathLabel_ocr">
<property name="geometry">
<rect>
<x>100</x>
<y>0</y>
<width>381</width>
<height>18</height>
</rect>
</property>
<property name="text">
<string>Path to image: </string>
</property>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>0</x>
<y>30</y>
<width>571</width>
<height>18</height>
</rect>
</property>
<property name="text">
<string>Here is recognised check text. Please, edit it if something's wrong:</string>
</property>
</widget>
<widget class="QLabel" name="picture_ocr">
<property name="geometry">
<rect>
<x>490</x>
<y>10</y>
<width>291</width>
<height>421</height>
</rect>
</property>
<property name="text">
<string/>
</property>
</widget>
</widget>
<widget class="QWidget" name="OFD">
<attribute name="title">
<string>OFD</string>
</attribute>
<widget class="QLabel" name="picture_ofd">
<property name="geometry">
<rect>
<x>490</x>
<y>10</y>
<width>291</width>
<height>421</height>
</rect>
</property>
<property name="text">
<string/>
</property>
</widget>
<widget class="QLabel" name="pathLabel_ofd">
<property name="geometry">
<rect>
<x>100</x>
<y>0</y>
<width>381</width>
<height>18</height>
</rect>
</property>
<property name="text">
<string>Path to image: </string>
</property>
</widget>
<widget class="QPushButton" name="chooseImageButton_ofd">
<property name="geometry">
<rect>
<x>10</x>
<y>0</y>
<width>80</width>
<height>26</height>
</rect>
</property>
<property name="text">
<string>Choose</string>
</property>
</widget>
<widget class="QLineEdit" name="fn_edit">
<property name="geometry">
<rect>
<x>180</x>
<y>50</y>
<width>261</width>
<height>26</height>
</rect>
</property>
<property name="inputMask">
<string>0000000000000000</string>
</property>
</widget>
<widget class="QLabel" name="fn_label">
<property name="geometry">
<rect>
<x>10</x>
<y>50</y>
<width>161</width>
<height>21</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>FN (Fiscal Number)</string>
</property>
</widget>
<widget class="QLabel" name="fd_label">
<property name="geometry">
<rect>
<x>10</x>
<y>90</y>
<width>161</width>
<height>21</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>FD (Fiscal Document)</string>
</property>
</widget>
<widget class="QLineEdit" name="fd_edit">
<property name="geometry">
<rect>
<x>180</x>
<y>90</y>
<width>261</width>
<height>26</height>
</rect>
</property>
<property name="inputMask">
<string>0000000000</string>
</property>
</widget>
<widget class="QLabel" name="fi_label">
<property name="geometry">
<rect>
<x>10</x>
<y>130</y>
<width>161</width>
<height>21</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>FI (Fiscal Identifier)</string>
</property>
</widget>
<widget class="QLineEdit" name="fi_edit">
<property name="geometry">
<rect>
<x>180</x>
<y>130</y>
<width>261</width>
<height>26</height>
</rect>
</property>
<property name="inputMask">
<string>0000000000</string>
</property>
</widget>
<widget class="QDateTimeEdit" name="dateTimeEdit">
<property name="geometry">
<rect>
<x>10</x>
<y>170</y>
<width>194</width>
<height>27</height>
</rect>
</property>
</widget>
<widget class="QComboBox" name="fundIncomeCombo">
<property name="geometry">
<rect>
<x>10</x>
<y>210</y>
<width>191</width>
<height>26</height>
</rect>
</property>
<item>
<property name="text">
<string>Funds income</string>
</property>
</item>
<item>
<property name="text">
<string>Funds return</string>
</property>
</item>
<item>
<property name="text">
<string>Funds spend</string>
</property>
</item>
<item>
<property name="text">
<string>Spends return</string>
</property>
</item>
</widget>
<widget class="QLineEdit" name="total_edit">
<property name="geometry">
<rect>
<x>90</x>
<y>250</y>
<width>113</width>
<height>26</height>
</rect>
</property>
<property name="inputMask">
<string/>
</property>
</widget>
<widget class="QLabel" name="total_label">
<property name="geometry">
<rect>
<x>10</x>
<y>250</y>
<width>66</width>
<height>18</height>
</rect>
</property>
<property name="text">
<string>Total</string>
</property>
</widget>
</widget>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>817</width>
<height>23</height>
</rect>
</property>
<widget class="QMenu" name="menuchecks_parser">
<property name="title">
<string>checks parser</string>
</property>
</widget>
<addaction name="menuchecks_parser"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>

10
media.qrc Normal file
View File

@ -0,0 +1,10 @@
<RCC>
<qresource prefix="/icons">
<file>assets/icons/email-text.svg</file>
<file>assets/icons/OCR.svg</file>
<file>assets/icons/OFD.svg</file>
<file>assets/icons/icon.png</file>
<file>assets/icons/icon.svg</file>
<file>assets/icons/settings.svg</file>
</qresource>
</RCC>

View File

@ -1,8 +0,0 @@
{
"name":"Магнит",
"goods_name_regex": "([\\(\\)\\%\\*a-zA-Z0-9\u0401\u0451\u0410-\u044f \\.\\-\/]{17,100})",
"goods_price_regex": "[0-9]{0,4}[^%]\\.[0-9]{2} ",
"goods_quantity_regex": "([0-9]{0,4}[^%]\\.[0-9]{3} )|(\t\\d )",
"check_start_regex": "",
"check_end_regex":""
}

View File

@ -1,8 +0,0 @@
{
"name":"Пятёрочка",
"goods_name_regex": "([\\(\\)\\%\\*a-zA-Z0-9\u0401\u0451\u0410-\u044f \\.\\-\/]{17,100})",
"goods_price_regex": "[0-9]{0,4}[^%]\\.[0-9]{2} ",
"goods_quantity_regex": "([0-9]{0,4}[^%]\\.[0-9]{3} )|(\t\\d )",
"check_start_regex": "КАССОВЫЙ ЧЕК\nприход",
"check_end_regex": "Итог\\:.{0,3}[0-9]{0,6}\\.[0-9]{2}"
}

View File

@ -1,11 +1,15 @@
#include "net.h" #include <net/net.h>
#include <curl/curl.h> #include <curl/curl.h>
#include "../utils/utils.h" #include <utils/utils.h>
#include <iostream> #include <iostream>
#include <vector>
#include <regex>
struct data {}; Net::Net() {}
size_t writeCallback(void* contents, size_t size, size_t nmemb, void* userp) {
size_t totalSize = size * nmemb;
((std::string*)userp)->append(std::string((char*)contents));
return totalSize;
}
size_t write_data(void *buffer, size_t size, size_t nmemb, void *filename) { size_t write_data(void *buffer, size_t size, size_t nmemb, void *filename) {
FILE *f = fopen(((std::string *)filename)->c_str(), "w"); FILE *f = fopen(((std::string *)filename)->c_str(), "w");
@ -16,44 +20,6 @@ size_t write_data(void *buffer, size_t size, size_t nmemb, void *filename) {
return written; return written;
} }
Net::Net() {}
void write_modules(void *buffer, size_t size, size_t nmemb, void *modules) {
std::vector<std::string> *modules_vector =
(std::vector<std::string> *)modules;
std::string to_parse = std::string((char*)buffer);
std::regex r("(?!\\\")\\w+\\.json(?!\\\")", std::regex::collate);
std::smatch res;
std::string::const_iterator search(to_parse.cbegin());
while (std::regex_search(search, to_parse.cend(), res, r)) {
modules_vector->push_back(res[0]);
search = res.suffix().first;
}
}
size_t writeCallback(void* contents, size_t size, size_t nmemb, void* userp) {
size_t totalSize = size * nmemb;
((std::string*)userp)->append(std::string((char*)contents));
return totalSize;
}
std::vector<std::string> Net::get_all_modules(std::string url) {
CURL *handle = curl_easy_init();
curl_easy_setopt(handle, CURLOPT_URL, url.c_str());
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_modules);
std::vector<std::string> modules {};
curl_easy_setopt(handle, CURLOPT_WRITEDATA, &modules);
curl_easy_perform(handle);
return modules;
}
void Net::get_file(std::string url, std::string filename) { void Net::get_file(std::string url, std::string filename) {
CURL *handle = curl_easy_init(); CURL *handle = curl_easy_init();

View File

@ -5,12 +5,12 @@
#include <vector> #include <vector>
size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp); size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp);
size_t writeCallback(void* contents, size_t size, size_t nmemb, void* userp);
class Net class Net
{ {
public: public:
Net(); Net();
std::vector<std::string> get_all_modules(std::string url);
void get_file(std::string url, std::string filename); void get_file(std::string url, std::string filename);
std::string fetch_check_data_from_ofdru(std::string fn, std::string fd, std::string fi, std::string datetime, int operation, int total, std::string captcha); std::string fetch_check_data_from_ofdru(std::string fn, std::string fd, std::string fi, std::string datetime, int operation, int total, std::string captcha);
void get_captcha_from_ofdru(); void get_captcha_from_ofdru();

View File

@ -83,8 +83,7 @@ void OutputDialog::on_buttonBox_accepted() {
output_file << std::fixed << std::setprecision(2) << goods.get_quantity(); output_file << std::fixed << std::setprecision(2) << goods.get_quantity();
break; break;
case ColumnType::goods_net_weight: case ColumnType::goods_net_weight:
output_file << "TODO"; output_file << goods.get_net_weight();
// TODO
break; break;
case ColumnType::goods_total: case ColumnType::goods_total:
output_file << std::fixed << std::setprecision(2) << goods.calculate_total_price(); output_file << std::fixed << std::setprecision(2) << goods.calculate_total_price();

View File

@ -1,215 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>OutputDialog</class>
<widget class="QDialog" name="OutputDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>586</width>
<height>431</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="geometry">
<rect>
<x>410</x>
<y>390</y>
<width>166</width>
<height>26</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
<widget class="QLabel" name="pathLabel">
<property name="geometry">
<rect>
<x>10</x>
<y>20</y>
<width>271</width>
<height>18</height>
</rect>
</property>
<property name="text">
<string>Path to export: </string>
</property>
</widget>
<widget class="QPushButton" name="chooseFileButton">
<property name="geometry">
<rect>
<x>290</x>
<y>20</y>
<width>80</width>
<height>26</height>
</rect>
</property>
<property name="text">
<string>Choose</string>
</property>
</widget>
<widget class="QCheckBox" name="printHeaderCheckBox">
<property name="geometry">
<rect>
<x>10</x>
<y>50</y>
<width>371</width>
<height>24</height>
</rect>
</property>
<property name="text">
<string>Print header</string>
</property>
</widget>
<widget class="QTableWidget" name="tableWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>130</y>
<width>401</width>
<height>221</height>
</rect>
</property>
<row>
<property name="text">
<string>Goods name</string>
</property>
</row>
<row>
<property name="text">
<string>Goods price</string>
</property>
</row>
<row>
<property name="text">
<string>Goods quantity</string>
</property>
</row>
<row>
<property name="text">
<string>Goods net weight</string>
</property>
</row>
<row>
<property name="text">
<string>Goods total</string>
</property>
</row>
<column>
<property name="text">
<string>position</string>
</property>
</column>
<column>
<property name="text">
<string>name</string>
</property>
</column>
<item row="0" column="0">
<property name="text">
<string>1</string>
</property>
</item>
<item row="0" column="1">
<property name="text">
<string>Name</string>
</property>
</item>
<item row="1" column="0">
<property name="text">
<string>2</string>
</property>
</item>
<item row="1" column="1">
<property name="text">
<string>Price</string>
</property>
</item>
<item row="2" column="0">
<property name="text">
<string>3</string>
</property>
</item>
<item row="2" column="1">
<property name="text">
<string>Quantity</string>
</property>
</item>
<item row="3" column="0">
<property name="text">
<string>4</string>
</property>
</item>
<item row="3" column="1">
<property name="text">
<string>Net weight</string>
</property>
</item>
<item row="4" column="0">
<property name="text">
<string>5</string>
</property>
</item>
<item row="4" column="1">
<property name="text">
<string>Total price</string>
</property>
</item>
</widget>
<widget class="QCheckBox" name="printTotalCheckBox">
<property name="geometry">
<rect>
<x>10</x>
<y>90</y>
<width>381</width>
<height>24</height>
</rect>
</property>
<property name="text">
<string>Print total</string>
</property>
</widget>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>OutputDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>OutputDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -1,93 +0,0 @@
#include "module.h"
#include <fstream>
#include <nlohmann/json.hpp>
#include <regex>
#include <string>
#include "../utils/utils.h"
StoreModule::StoreModule() {}
StoreModule::StoreModule(std::string path) {
std::ifstream settings_file(path);
nlohmann::json settings = nlohmann::json::parse(settings_file);
this->name = from_utf8(settings["name"]);
this->goods_name_regex = from_utf8(settings["goods_name_regex"]);
this->goods_price_regex = from_utf8(settings["goods_price_regex"]);
this->goods_quantity_regex = from_utf8(settings["goods_quantity_regex"]);
this->check_start_regex = from_utf8(settings["check_start_regex"]);
this->check_end_regex = from_utf8(settings["check_end_regex"]);
#ifdef DEBUG
std::wcout << "Name: " << this->name << std::endl;
std::wcout << "Goods name regex: " << this->goods_name_regex << std::endl;
std::wcout << "Goods price regex: " << this->goods_price_regex << std::endl;
std::wcout << "Goods quantity regex: " << this->goods_quantity_regex
<< std::endl;
std::wcout << "Check start regex: " << this->check_start_regex << std::endl;
std::wcout << "Check end regex: " << this->check_end_regex << std::endl;
#endif
}
std::vector<std::string> StoreModule::parse_name(std::wstring str) {
std::vector<std::string> result;
std::wregex r(this->goods_name_regex, std::regex::collate);
for (std::wsregex_iterator it{str.begin(), str.end(), r}, end{}; it != end;
it++) {
result.push_back(to_utf8(it->str()));
}
return result;
}
std::vector<std::string> StoreModule::parse_price(std::wstring str) {
std::vector<std::string> result;
std::wregex r(this->goods_price_regex, std::regex::collate);
for (std::wsregex_iterator it{str.begin(), str.end(), r}, end{}; it != end;
it++) {
result.push_back(to_utf8(it->str()));
}
return result;
}
std::vector<std::string> StoreModule::parse_quantity(std::wstring str) {
std::vector<std::string> result;
std::wregex r(this->goods_quantity_regex, std::regex::collate);
for (std::wsregex_iterator it{str.begin(), str.end(), r}, end{}; it != end;
it++) {
result.push_back(to_utf8(it->str()));
}
return result;
}
std::wstring StoreModule::trim_check(std::wstring& check) {
unsigned int start_pos;
unsigned int end_pos;
std::wregex start_regex(this->check_start_regex, std::regex::collate);
std::wregex end_regex(this->check_end_regex, std::regex::collate);
for (std::wsregex_iterator it{check.begin(), check.end(), start_regex}, end{};
it != end; it++) {
start_pos = it->position() + it->str().size();
break;
}
check = check.substr(start_pos, check.size());
for (std::wsregex_iterator it{check.begin(), check.end(), end_regex}, end{};
it != end; it++) {
end_pos = it->position() - 1;
break;
}
check = check.substr(0, end_pos);
return check;
}
std::wstring StoreModule::get_name() { return this->name; }

View File

@ -1,28 +0,0 @@
#ifndef STORE_MODULE_H
#define STORE_MODULE_H
#include <string>
#include <vector>
class StoreModule {
std::string path;
std::wstring name;
std::wstring goods_name_regex;
std::wstring goods_price_regex;
std::wstring goods_quantity_regex;
std::wstring check_start_regex;
std::wstring check_end_regex;
public:
StoreModule(std::string);
StoreModule();
std::vector<std::string> parse_name(std::wstring);
std::vector<std::string> parse_price(std::wstring);
std::vector<std::string> parse_quantity(std::wstring);
std::wstring trim_check(std::wstring&);
std::wstring get_name();
};
#endif // STORE_MODULE_H

View File

@ -1,103 +0,0 @@
#include "parser.h"
#include "../goods/goods.h"
#include "../net/net.h"
#include "../settings/settings.h"
#include "../utils/utils.h"
#include <iostream>
#if __GNUC__ < 8 && __clang_major__ < 17
# include <experimental/filesystem>
using namespace std::experimental;
using namespace std::experimental::filesystem;
#else
# include <filesystem>
using namespace std::filesystem;
#endif
Parser::Parser() {}
std::vector<std::string> Parser::search_modules() {
Settings s(get_path_relative_to_home(".local/share/checks_parser/settings.json"));
std::string path = get_path_relative_to_home(s.get_setting("stores_modules_dir"));//std::string(std::getenv("HOME")) + "/" + STORES_MODULES_DIR;
directory_entry modules_dir(path);
if (!exists(modules_dir)) {
create_directories(path);
std::cout << "No modules directory found. Created one at " << path
<< std::endl;
std::cout << "Please, download modules to that directory from my git."
<< std::endl;
}
std::vector<std::string> modules_files;
for (auto file : directory_iterator(path)) {
modules_files.push_back(file.path());
}
return modules_files;
}
void Parser::set_module(std::string path) { module = StoreModule(path); }
std::vector<Goods> Parser::parse(std::wstring check_plaintext) {
std::vector<Goods> result;
module.trim_check(check_plaintext);
std::vector<std::string> goods_names = module.parse_name(check_plaintext);
std::vector<std::string> goods_prices = module.parse_price(check_plaintext);
std::vector<std::string> goods_quantities =
module.parse_quantity(check_plaintext);
if (goods_names.size() != goods_prices.size() ||
goods_names.size() != goods_quantities.size() ||
goods_prices.size() != goods_quantities.size()) {
//Error. Amount of names, prices or quantities are not equal. That means, that some regex(es) has mismatched.
return {};
}
short goods_amount = goods_names.size();
for (short i = 0; i < goods_amount; i++) {
Goods goods(goods_names[i], std::stof(goods_prices[i]), std::stof(goods_quantities[i]));
result.push_back(goods);
}
return result;
}
std::vector<std::string> Parser::check_updates() {
std::cout << "Checking updates for stores modules" << std::endl;
Settings s(get_path_relative_to_home(".local/share/checks_parser/settings.json"));
std::string path = get_path_relative_to_home(s.get_setting("stores_modules_dir"));
std::vector<std::string> to_download;
std::vector<std::string> stored_modules;
directory_entry modules_dir(path);
if (!exists(modules_dir)) {
create_directories(path);
}
for (const auto& file : directory_iterator(path)) {
if (!is_regular_file(file)) continue;
stored_modules.push_back(file.path().filename());
std::cout << file.path().filename() << " detected store module" << std::endl;
}
Net n;
std::cerr << "Downloading modules list from: " << s.get_setting("stores_modules_url") << std::endl;
std::vector<std::string> remote_modules = n.get_all_modules(s.get_setting("stores_modules_url"));
if (stored_modules.empty()) {
std::cout << "I need to download everything" << std::endl;
to_download = remote_modules;
} else {
for (const std::string& module : remote_modules) {
if (!vector_contains_element(stored_modules, module)) {
std::cout << "I need to download store module " << module << std::endl;
to_download.push_back(module);
}
}
}
return to_download;
}

View File

@ -1,25 +0,0 @@
#ifndef PARSER_H
#define PARSER_H
#include "../goods/goods.h"
#include "module.h"
#include <string>
#include <vector>
class Parser {
StoreModule module;
public:
Parser();
std::vector<std::string> search_modules();
std::vector<std::string> check_updates();
void set_module(std::string);
std::vector<Goods> parse(std::wstring);
};
#endif // PARSER_H

8
scenes.qrc Normal file
View File

@ -0,0 +1,8 @@
<RCC>
<qresource prefix="/scenes">
<file>scenes/outputdialog.ui</file>
<file>scenes/mainwindow.ui</file>
<file>scenes/settingsdialog.ui</file>
<file>scenes/solvecaptchadialog.ui</file>
</qresource>
</RCC>

View File

@ -13,65 +13,42 @@
<property name="windowTitle"> <property name="windowTitle">
<string>Dialog</string> <string>Dialog</string>
</property> </property>
<widget class="QDialogButtonBox" name="buttonBox"> <layout class="QGridLayout" name="gridLayout">
<property name="geometry"> <item row="1" column="0" colspan="2">
<rect> <widget class="ImageRedactor" name="graphicsView"/>
<x>450</x> </item>
<y>450</y> <item row="2" column="0">
<width>341</width> <widget class="QSlider" name="contrastSlider">
<height>32</height> <property name="value">
</rect> <number>50</number>
</property> </property>
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Orientation::Horizontal</enum>
</property> </property>
<property name="standardButtons"> </widget>
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> </item>
</property> <item row="0" column="0" colspan="2">
</widget> <widget class="QLabel" name="label">
<widget class="QSlider" name="contrastSlider"> <property name="text">
<property name="geometry"> <string>Please, zoom to qr code and adjust contrast so that qr code looks sharp</string>
<rect> </property>
<x>10</x> </widget>
<y>460</y> </item>
<width>591</width> <item row="3" column="0">
<height>16</height> <widget class="QDialogButtonBox" name="buttonBox">
</rect> <property name="orientation">
</property> <enum>Qt::Orientation::Horizontal</enum>
<property name="value"> </property>
<number>50</number> <property name="standardButtons">
</property> <set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
<property name="orientation"> </property>
<enum>Qt::Horizontal</enum> </widget>
</property> </item>
</widget> </layout>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>10</x>
<y>0</y>
<width>511</width>
<height>18</height>
</rect>
</property>
<property name="text">
<string>Please, zoom to qr code and adjust contrast so that qr code looks sharp</string>
</property>
</widget>
<widget class="ImageRedactor" name="graphicsView">
<property name="geometry">
<rect>
<x>5</x>
<y>21</y>
<width>801</width>
<height>421</height>
</rect>
</property>
</widget>
<zorder>buttonBox</zorder>
<zorder>label</zorder> <zorder>label</zorder>
<zorder>contrastSlider</zorder> <zorder>contrastSlider</zorder>
<zorder>graphicsView</zorder> <zorder>graphicsView</zorder>
<zorder>buttonBox</zorder>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>

254
scenes/mainwindow.ui Normal file
View File

@ -0,0 +1,254 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QWidget" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1039</width>
<height>426</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>971</width>
<height>0</height>
</size>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="3">
<widget class="QLabel" name="or_label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>or</string>
</property>
</widget>
</item>
<item row="9" column="0" colspan="5">
<widget class="QPushButton" name="parse_button">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Parse</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="fd_label">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>FD (Fiscal Document)</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="fn_label">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>FN (Fiscal Number)</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="operation_type_label">
<property name="text">
<string>Operation type</string>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QPushButton" name="binary_eye_button">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Use your phone as a QR code scanner</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="5">
<widget class="QLabel" name="info_label">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="datetime_label">
<property name="text">
<string>Date and time of purchase</string>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QPushButton" name="stop_server_button">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Stop server</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="choose_image_button">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Choose image on your PC</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="total_label">
<property name="text">
<string>Total</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="fi_label">
<property name="text">
<string>FI (Fiscal Identifier)</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="parse_email_button">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Parse an E-Mail</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="or_label_1">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>or</string>
</property>
</widget>
</item>
<item row="3" column="2" colspan="3">
<widget class="QLineEdit" name="fn_line_edit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="4" column="2" colspan="3">
<widget class="QLineEdit" name="fd_line_edit"/>
</item>
<item row="5" column="2" colspan="3">
<widget class="QLineEdit" name="fi_line_edit"/>
</item>
<item row="6" column="2" colspan="3">
<widget class="QDateTimeEdit" name="purchase_datetime_edit"/>
</item>
<item row="7" column="2" colspan="3">
<widget class="QComboBox" name="operation_type_combo_box">
<item>
<property name="text">
<string>Funds income</string>
</property>
</item>
<item>
<property name="text">
<string>Funds return</string>
</property>
</item>
<item>
<property name="text">
<string>Funds spend</string>
</property>
</item>
<item>
<property name="text">
<string>Spends return</string>
</property>
</item>
</widget>
</item>
<item row="8" column="2" colspan="3">
<widget class="QDoubleSpinBox" name="total_spin_box">
<property name="maximum">
<double>4294967296.000000000000000</double>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QPushButton" name="settings_button">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Settings</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

187
scenes/outputdialog.ui Normal file
View File

@ -0,0 +1,187 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>OutputDialog</class>
<widget class="QDialog" name="OutputDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>892</width>
<height>537</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="pathLabel">
<property name="text">
<string>Path to export: </string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="chooseFileButton">
<property name="text">
<string>Choose</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="printHeaderCheckBox">
<property name="text">
<string>Print header</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="printTotalCheckBox">
<property name="text">
<string>Print total</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="3">
<widget class="QTableWidget" name="tableWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<row>
<property name="text">
<string>Goods name</string>
</property>
</row>
<row>
<property name="text">
<string>Goods price</string>
</property>
</row>
<row>
<property name="text">
<string>Goods quantity</string>
</property>
</row>
<row>
<property name="text">
<string>Goods net weight</string>
</property>
</row>
<row>
<property name="text">
<string>Goods total</string>
</property>
</row>
<column>
<property name="text">
<string>position</string>
</property>
</column>
<column>
<property name="text">
<string>name</string>
</property>
</column>
<item row="0" column="0">
<property name="text">
<string>1</string>
</property>
</item>
<item row="0" column="1">
<property name="text">
<string>Name</string>
</property>
</item>
<item row="1" column="0">
<property name="text">
<string>2</string>
</property>
</item>
<item row="1" column="1">
<property name="text">
<string>Price</string>
</property>
</item>
<item row="2" column="0">
<property name="text">
<string>3</string>
</property>
</item>
<item row="2" column="1">
<property name="text">
<string>Quantity</string>
</property>
</item>
<item row="3" column="0">
<property name="text">
<string>4</string>
</property>
</item>
<item row="3" column="1">
<property name="text">
<string>Net weight</string>
</property>
</item>
<item row="4" column="0">
<property name="text">
<string>5</string>
</property>
</item>
<item row="4" column="1">
<property name="text">
<string>Total price</string>
</property>
</item>
</widget>
</item>
<item row="4" column="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>OutputDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>OutputDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

236
scenes/settingsdialog.ui Normal file
View File

@ -0,0 +1,236 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>settingsdialog</class>
<widget class="QDialog" name="settingsdialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>693</width>
<height>616</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QScrollArea" name="scrollArea">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>673</width>
<height>554</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout">
<item row="5" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Goods quantity alias</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QSpinBox" name="goodsTotalPositionSpin"/>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="goodsNameAliasEdit"/>
</item>
<item row="12" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Language</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_16">
<property name="text">
<string>Goods net weight alias</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Goods price per unit alias</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="goodsQuantityAliasEdit"/>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Print total</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Goods name alias</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="goodsPricePerUnitAliasEdit"/>
</item>
<item row="9" column="1">
<widget class="QLineEdit" name="goodsTotalAliasEdit"/>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="goodsQuantityPositionSpin"/>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>Goods total alias</string>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Print header</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLineEdit" name="goodsNetWeightAliasEdit"/>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
<string>Goods total position</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QSpinBox" name="goodsNetWeightPositionSpin"/>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Goods net weight position</string>
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="QComboBox" name="languageComboBox">
<item>
<property name="text">
<string>en_US</string>
</property>
</item>
<item>
<property name="text">
<string>ru_RU</string>
</property>
</item>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Goods quantity position</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="goodsNamePositionSpin"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Goods name position</string>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QCheckBox" name="printHeaderCheckBox">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Goods price per unit position</string>
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QCheckBox" name="printTotalCheckBox">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="goodsPricePerUnitPositionSpin"/>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
<item row="1" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Save</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>settingsdialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>settingsdialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -4,7 +4,7 @@
#include <string> #include <string>
#include "../utils/utils.h" #include "../utils/utils.h"
#if __GNUC__ < 8 && __clang_major__ < 17 #if __GNUC__ <= 8 && __clang_major__ < 17
# include <experimental/filesystem> # include <experimental/filesystem>
using namespace std::experimental; using namespace std::experimental;
using namespace std::experimental::filesystem; using namespace std::experimental::filesystem;
@ -20,10 +20,6 @@ Settings::Settings(std::string path) {
std::ofstream output(path); std::ofstream output(path);
nlohmann::json settings = R"({ nlohmann::json settings = R"({
"ofds_modules_dir":".local/share/checks_parser/modules/ofd",
"stores_modules_dir":".local/share/checks_parser/modules/stores",
"ofds_modules_url":"https://foxarmy.org/checks-parser/modules/ofd/",
"stores_modules_url":"https://foxarmy.org/checks-parser/modules/stores/",
"print_header": true, "print_header": true,
"print_total": true, "print_total": true,
"output_order": { "output_order": {

View File

@ -1,7 +1,10 @@
#include "settingsdialog.h" #include "settingsdialog.h"
#include "settings/settings.h"
#include "ui_settingsdialog.h" #include "ui_settingsdialog.h"
#include "utils/utils.h"
#include <settings/settings.h>
#include <utils/utils.h>
#include <iostream>
#include <QMessageBox> #include <QMessageBox>
@ -12,11 +15,6 @@ SettingsDialog::SettingsDialog(QWidget *parent)
ui->setupUi(this); ui->setupUi(this);
ui->OFDModulesDirEdit->setText(QString::fromStdString(settings.get_all_settings()["ofds_modules_dir"]));
ui->OFDModulesURLEdit->setText(QString::fromStdString(settings.get_all_settings()["ofds_modules_url"]));
ui->storesModulesDirEdit->setText(QString::fromStdString(settings.get_all_settings()["stores_modules_dir"]));
ui->storesModulesURLEdit->setText(QString::fromStdString(settings.get_all_settings()["stores_modules_url"]));
ui->goodsNamePositionSpin->setValue(this->settings.get_all_settings()["output_order"]["goods_name"]["position"]); ui->goodsNamePositionSpin->setValue(this->settings.get_all_settings()["output_order"]["goods_name"]["position"]);
ui->goodsNameAliasEdit->setText(QString::fromStdString(this->settings.get_all_settings()["output_order"]["goods_name"]["name"])); ui->goodsNameAliasEdit->setText(QString::fromStdString(this->settings.get_all_settings()["output_order"]["goods_name"]["name"]));
@ -35,42 +33,24 @@ SettingsDialog::SettingsDialog(QWidget *parent)
ui->printHeaderCheckBox->setChecked(this->settings.get_all_settings()["print_header"]); ui->printHeaderCheckBox->setChecked(this->settings.get_all_settings()["print_header"]);
ui->printTotalCheckBox->setChecked(this->settings.get_all_settings()["print_total"]); ui->printTotalCheckBox->setChecked(this->settings.get_all_settings()["print_total"]);
int currentLanguageIndex = 0; int currentLanguageIndex = 0;
if (!this->settings.get_all_settings().contains("language")) { bool languageSettingPresent = false;
languageSettingPresent = settings.get_all_settings().find("language") != settings.get_all_settings().end();
if (languageSettingPresent) {
currentLanguageIndex = ui->languageComboBox->findText(QString::fromStdString(this->settings.get_all_settings()["language"]));
} else {
currentLanguageIndex = ui->languageComboBox->findText(QLocale::system().name()); currentLanguageIndex = ui->languageComboBox->findText(QLocale::system().name());
if (currentLanguageIndex < 0) { if (currentLanguageIndex < 0) {
currentLanguageIndex = ui->languageComboBox->findText("en_US"); currentLanguageIndex = ui->languageComboBox->findText("en_US");
} }
} else {
currentLanguageIndex = ui->languageComboBox->findText(QString::fromStdString(this->settings.get_all_settings()["language"]));
} }
ui->languageComboBox->setCurrentIndex(currentLanguageIndex); ui->languageComboBox->setCurrentIndex(currentLanguageIndex);
} }
SettingsDialog::~SettingsDialog() { delete ui; }
void SettingsDialog::on_OFDModulesDirEdit_editingFinished() {
this->settings.alter_setting("ofds_modules_dir",
ui->OFDModulesDirEdit->text().toStdString());
}
void SettingsDialog::on_storesModulesDirEdit_editingFinished() {
this->settings.alter_setting("stores_modules_dir",
ui->storesModulesDirEdit->text().toStdString());
}
void SettingsDialog::on_OFDModulesURLEdit_editingFinished() {
this->settings.alter_setting("ofds_modules_url",
ui->OFDModulesURLEdit->text().toStdString());
}
void SettingsDialog::on_storesModulesURLEdit_editingFinished() {
this->settings.alter_setting("stores_modules_url",
ui->storesModulesURLEdit->text().toStdString());
}
void SettingsDialog::on_goodsNamePositionSpin_valueChanged(int value) { void SettingsDialog::on_goodsNamePositionSpin_valueChanged(int value) {
this->settings.get_all_settings()["output_order"]["goods_name"]["position"] = this->settings.get_all_settings()["output_order"]["goods_name"]["position"] =
value; value;
@ -137,7 +117,11 @@ void SettingsDialog::on_buttonBox_accepted() { this->settings.flush(); }
void SettingsDialog::on_buttonBox_rejected() { this->close(); } void SettingsDialog::on_buttonBox_rejected() { this->close(); }
void SettingsDialog::on_languageComboBox_currentTextChanged(const QString &changed) { void SettingsDialog::on_languageComboBox_currentTextChanged(const QString &changed) {
if (this->settings.get_all_settings().contains("language")) { bool languageSettingPresent = false;
languageSettingPresent = settings.get_all_settings().find("language") != settings.get_all_settings().end();
if (languageSettingPresent) {
if (changed == QString::fromStdString(this->settings.get_all_settings()["language"])) return; if (changed == QString::fromStdString(this->settings.get_all_settings()["language"])) return;
} else { } else {
if (changed == QLocale::system().name()) return; if (changed == QLocale::system().name()) return;
@ -152,3 +136,5 @@ void SettingsDialog::on_languageComboBox_currentTextChanged(const QString &chang
infoDialog.exec(); infoDialog.exec();
} }
SettingsDialog::~SettingsDialog() { delete ui; }

View File

@ -2,7 +2,7 @@
#define SETTINGSDIALOG_H #define SETTINGSDIALOG_H
#include <QDialog> #include <QDialog>
#include "settings/settings.h" #include <settings/settings.h>
namespace Ui { namespace Ui {
class settingsdialog; class settingsdialog;
@ -16,46 +16,35 @@ public:
~SettingsDialog(); ~SettingsDialog();
private slots: private slots:
void on_OFDModulesDirEdit_editingFinished();
void on_buttonBox_accepted();
void on_storesModulesDirEdit_editingFinished();
void on_OFDModulesURLEdit_editingFinished();
void on_storesModulesURLEdit_editingFinished();
void on_goodsNamePositionSpin_valueChanged(int arg1); void on_goodsNamePositionSpin_valueChanged(int arg1);
void on_goodsNameAliasEdit_editingFinished(); void on_goodsNameAliasEdit_editingFinished();
void on_goodsPricePerUnitPositionSpin_valueChanged(int arg1); void on_goodsPricePerUnitPositionSpin_valueChanged(int arg1);
void on_goodsPricePerUnitAliasEdit_editingFinished(); void on_goodsPricePerUnitAliasEdit_editingFinished();
void on_goodsQuantityPositionSpin_valueChanged(int arg1); void on_goodsQuantityPositionSpin_valueChanged(int arg1);
void on_goodsQuantityAliasEdit_editingFinished(); void on_goodsQuantityAliasEdit_editingFinished();
void on_goodsNetWeightPositionSpin_valueChanged(int arg1); void on_goodsNetWeightPositionSpin_valueChanged(int arg1);
void on_goodsNetWeightAliasEdit_editingFinished(); void on_goodsNetWeightAliasEdit_editingFinished();
void on_goodsTotalPositionSpin_valueChanged(int arg1);
void on_goodsTotalPositionSpin_valueChanged(int arg1);
void on_goodsTotalAliasEdit_editingFinished(); void on_goodsTotalAliasEdit_editingFinished();
void on_printTotalCheckBox_stateChanged(int arg1);
void on_printHeaderCheckBox_stateChanged(int arg1); void on_printHeaderCheckBox_stateChanged(int arg1);
void on_printTotalCheckBox_stateChanged(int arg1); void on_buttonBox_accepted();
void on_buttonBox_rejected(); void on_buttonBox_rejected();
void on_languageComboBox_currentTextChanged(const QString &arg1); void on_languageComboBox_currentTextChanged(const QString &arg1);
private: private:
Ui::settingsdialog *ui; Ui::settingsdialog *ui;
public:
bool settingsExist();
}; };
#endif // SETTINGSDIALOG_H #endif // SETTINGSDIALOG_H

View File

@ -1,306 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>settingsdialog</class>
<widget class="QDialog" name="settingsdialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>599</width>
<height>799</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="geometry">
<rect>
<x>310</x>
<y>740</y>
<width>251</width>
<height>32</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
</property>
</widget>
<widget class="QScrollArea" name="scrollArea">
<property name="geometry">
<rect>
<x>10</x>
<y>0</y>
<width>541</width>
<height>741</height>
</rect>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>539</width>
<height>739</height>
</rect>
</property>
<widget class="QWidget" name="gridLayoutWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>531</width>
<height>731</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="15" column="1">
<widget class="QCheckBox" name="printTotalCheckBox">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Goods net weight position</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="goodsNamePositionSpin"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Stores modules url</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Goods quantity position</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="OFDModulesDirEdit"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>OFD modules url</string>
</property>
</widget>
</item>
<item row="14" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Print header</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QSpinBox" name="goodsPricePerUnitPositionSpin"/>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="storesModulesURLEdit"/>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Goods quantity alias</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>OFD modules directory</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="goodsNameAliasEdit"/>
</item>
<item row="15" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Print total</string>
</property>
</widget>
</item>
<item row="13" column="1">
<widget class="QLineEdit" name="goodsTotalAliasEdit"/>
</item>
<item row="8" column="1">
<widget class="QSpinBox" name="goodsQuantityPositionSpin"/>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_16">
<property name="text">
<string>Goods net weight alias</string>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QSpinBox" name="goodsNetWeightPositionSpin"/>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="OFDModulesURLEdit"/>
</item>
<item row="13" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>Goods total alias</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="storesModulesDirEdit"/>
</item>
<item row="7" column="1">
<widget class="QLineEdit" name="goodsPricePerUnitAliasEdit"/>
</item>
<item row="9" column="1">
<widget class="QLineEdit" name="goodsQuantityAliasEdit"/>
</item>
<item row="11" column="1">
<widget class="QLineEdit" name="goodsNetWeightAliasEdit"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Goods name position</string>
</property>
</widget>
</item>
<item row="14" column="1">
<widget class="QCheckBox" name="printHeaderCheckBox">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Goods name alias</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Goods price per unit position</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Stores modules directory</string>
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
<string>Goods total position</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="OFDModulesDirChooseButton">
<property name="text">
<string>Choose</string>
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="QSpinBox" name="goodsTotalPositionSpin"/>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Goods price per unit alias</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="storedModulesDirChooseButton">
<property name="text">
<string>Choose</string>
</property>
</widget>
</item>
<item row="16" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item row="16" column="1">
<widget class="QComboBox" name="languageComboBox">
<item>
<property name="text">
<string>en_US</string>
</property>
</item>
<item>
<property name="text">
<string>ru_RU</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</widget>
</widget>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>settingsdialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>settingsdialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -11,7 +11,6 @@ SolveCaptchaDialog::SolveCaptchaDialog(QWidget *parent, std::string* solved_capt
ui->setupUi(this); ui->setupUi(this);
QString captcha_path = QString::fromStdString(get_path_relative_to_home(".local/share/checks_parser/captcha.jpg")); QString captcha_path = QString::fromStdString(get_path_relative_to_home(".local/share/checks_parser/captcha.jpg"));
std::cout << captcha_path.toStdString() << std::endl;
ui->captcha_picture->setPixmap(captcha_path); ui->captcha_picture->setPixmap(captcha_path);
ui->captcha_picture->setScaledContents(true); ui->captcha_picture->setScaledContents(true);
} }

View File

@ -4,12 +4,12 @@
<context> <context>
<name>AdjustPictureDialog</name> <name>AdjustPictureDialog</name>
<message> <message>
<location filename="../adjustpicturedialog.ui" line="14"/> <location filename="../scenes/adjustpicturedialog.ui" line="14"/>
<source>Dialog</source> <source>Dialog</source>
<translation>Dialog</translation> <translation>Dialog</translation>
</message> </message>
<message> <message>
<location filename="../adjustpicturedialog.ui" line="58"/> <location filename="../scenes/adjustpicturedialog.ui" line="33"/>
<source>Please, zoom to qr code and adjust contrast so that qr code looks sharp</source> <source>Please, zoom to qr code and adjust contrast so that qr code looks sharp</source>
<translation>Please, zoom to qr code and adjust contrast so that qr code looks sharp</translation> <translation>Please, zoom to qr code and adjust contrast so that qr code looks sharp</translation>
</message> </message>
@ -24,309 +24,593 @@
<translation>No QR code</translation> <translation>No QR code</translation>
</message> </message>
</context> </context>
<context>
<name>EmailTextScene</name>
<message>
<source>Form</source>
<translation type="vanished">Form</translation>
</message>
<message>
<source>Store type</source>
<translation type="obsolete">Store type</translation>
</message>
<message>
<source>Check content</source>
<translation type="vanished">Check content</translation>
</message>
<message>
<source>Parse</source>
<translation type="vanished">Parse</translation>
</message>
<message>
<source>Store:</source>
<translation type="vanished">Store:</translation>
</message>
<message>
<source>Back</source>
<translation type="vanished">Back</translation>
</message>
<message>
<source>An error has occured. Check was matched incorrectly. Vector sizes are different. Please, contact the developer.</source>
<translation type="vanished">An error has occured. Check was matched incorrectly. Vector sizes are different. Please, contact the developer.</translation>
</message>
<message>
<source>Error in parsing</source>
<translation type="vanished">Error in parsing</translation>
</message>
</context>
<context> <context>
<name>MainWindow</name> <name>MainWindow</name>
<message> <message>
<location filename="../mainwindow.ui" line="14"/>
<source>MainWindow</source> <source>MainWindow</source>
<translation>Главное окно</translation> <translation type="vanished">Главное окно</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="37"/>
<source>Store type</source> <source>Store type</source>
<translation>Store type</translation> <translation type="vanished">Store type</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="50"/> <location filename="../scenes/mainwindow.ui" line="51"/>
<source>Parse</source> <source>Parse</source>
<translation>Parse</translation> <translation>Parse</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="63"/>
<source>Preferences</source> <source>Preferences</source>
<translation>Preferences</translation> <translation type="vanished">Preferences</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="80"/>
<source>Text</source> <source>Text</source>
<translation>Text</translation> <translation type="vanished">Text</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="92"/>
<source>Check content</source> <source>Check content</source>
<translation>Check content</translation> <translation type="vanished">Check content</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="108"/>
<source>OCR</source> <source>OCR</source>
<translatorcomment>OCR = Optical Character Recognition</translatorcomment> <translatorcomment>OCR = Optical Character Recognition</translatorcomment>
<translation>OCR</translation> <translation type="vanished">OCR</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="120"/>
<location filename="../mainwindow.ui" line="213"/>
<source>Choose</source> <source>Choose</source>
<translation>Choose</translation> <translation type="vanished">Choose</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="143"/>
<location filename="../mainwindow.ui" line="200"/>
<source>Path to image: </source> <source>Path to image: </source>
<translation>Path to image: </translation> <translation type="vanished">Path to image: </translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="156"/>
<source>Here is recognised check text. Please, edit it if something&apos;s wrong:</source> <source>Here is recognised check text. Please, edit it if something&apos;s wrong:</source>
<translation>Here is recognised check text. Please, edit it if something&apos;s wrong:</translation> <translation type="vanished">Here is recognised check text. Please, edit it if something&apos;s wrong:</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="175"/>
<source>OFD</source> <source>OFD</source>
<translatorcomment>OFD = Оператор Фискальных Данных</translatorcomment> <translatorcomment>OFD = Оператор Фискальных Данных</translatorcomment>
<translation>OFD</translation> <translation type="vanished">OFD</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="226"/>
<source>0000000000000000</source> <source>0000000000000000</source>
<translation>0000000000000000</translation> <translation type="vanished">0000000000000000</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="245"/> <location filename="../scenes/mainwindow.ui" line="77"/>
<source>FN (Fiscal Number)</source> <source>FN (Fiscal Number)</source>
<translatorcomment>FN = Фискальный Номер</translatorcomment> <translatorcomment>FN = Фискальный Номер</translatorcomment>
<translation>FN (Fiscal Number)</translation> <translation>FN (Fiscal Number)</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="264"/> <location filename="../scenes/mainwindow.ui" line="64"/>
<source>FD (Fiscal Document)</source> <source>FD (Fiscal Document)</source>
<translatorcomment>FD = Фискальный Документ</translatorcomment> <translatorcomment>FD = Фискальный Документ</translatorcomment>
<translation>FD (Fiscal Document)</translation> <translation>FD (Fiscal Document)</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="277"/>
<location filename="../mainwindow.ui" line="309"/>
<source>0000000000</source> <source>0000000000</source>
<translation>000000000</translation> <translation type="vanished">000000000</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="296"/> <source>Back</source>
<translation type="obsolete">Back</translation>
</message>
<message>
<location filename="../scenes/mainwindow.ui" line="130"/>
<source>Stop server</source>
<translation>Stop server</translation>
</message>
<message>
<location filename="../scenes/mainwindow.ui" line="143"/>
<source>Choose image on your PC</source>
<translation>Choose image on your PC</translation>
</message>
<message>
<location filename="../scenes/mainwindow.ui" line="38"/>
<location filename="../scenes/mainwindow.ui" line="183"/>
<source>or</source>
<translation>or</translation>
</message>
<message>
<location filename="../scenes/mainwindow.ui" line="97"/>
<source>Use your phone as a QR code scanner</source>
<translation>Use your phone as a QR code scanner</translation>
</message>
<message>
<location filename="../scenes/mainwindow.ui" line="157"/>
<source>FI (Fiscal Identifier)</source> <source>FI (Fiscal Identifier)</source>
<translatorcomment>FI = Фискальный Признак</translatorcomment> <translatorcomment>FI = Фискальный Признак</translatorcomment>
<translation>FI (Fiscal Identifier)</translation> <translation>FI (Fiscal Identifier)</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="333"/> <location filename="../scenes/mainwindow.ui" line="117"/>
<source>Date and time of purchase</source>
<translation>Date and time of purchase</translation>
</message>
<message>
<location filename="../scenes/mainwindow.ui" line="84"/>
<source>Operation type</source>
<translation>Operation type</translation>
</message>
<message>
<location filename="../scenes/mainwindow.ui" line="170"/>
<source>Parse an E-Mail</source>
<translation>Parse an E-Mail</translation>
</message>
<message>
<location filename="../scenes/mainwindow.ui" line="210"/>
<source>Funds income</source> <source>Funds income</source>
<translatorcomment>Приход средств</translatorcomment> <translatorcomment>Приход средств</translatorcomment>
<translation>Funds income</translation> <translation>Funds income</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="338"/> <location filename="../scenes/mainwindow.ui" line="215"/>
<source>Funds return</source> <source>Funds return</source>
<translatorcomment>Возврат средств</translatorcomment> <translatorcomment>Возврат средств</translatorcomment>
<translation>Funds return</translation> <translation>Funds return</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="343"/> <location filename="../scenes/mainwindow.ui" line="220"/>
<source>Funds spend</source> <source>Funds spend</source>
<translatorcomment>Расход средств</translatorcomment> <translatorcomment>Расход средств</translatorcomment>
<translation>Funds spend</translation> <translation>Funds spend</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="348"/> <location filename="../scenes/mainwindow.ui" line="225"/>
<source>Spends return</source> <source>Spends return</source>
<translatorcomment>Возврат расхода</translatorcomment> <translatorcomment>Возврат расхода</translatorcomment>
<translation>Spends return</translation> <translation>Spends return</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="375"/> <location filename="../scenes/mainwindow.ui" line="246"/>
<source>Settings</source>
<translation>Settings</translation>
</message>
<message>
<location filename="../scenes/mainwindow.ui" line="150"/>
<source>Total</source> <source>Total</source>
<translation>Total</translation> <translation>Total</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="392"/>
<source>checks parser</source> <source>checks parser</source>
<translation>checks parser</translation> <translation type="vanished">checks parser</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="85"/> <location filename="../mainwindow.cpp" line="91"/>
<source>QR code for binaryeye to connect</source>
<translation>QR code for binaryeye to connect</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="92"/>
<source>I&apos;ve scanned</source>
<translation>I&apos;ve scanned</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="98"/>
<source>Could not start http server. 10 times in a row random port was occupied. Either you should run for a lottery ticket, or the problem is in the program. If the lottery ticket wasn&apos;t lucky, please, contact the developer.</source>
<translation>Could not start http server. 10 times in a row random port was occupied. Either you should run for a lottery ticket, or the problem is in the program. If the lottery ticket wasn&apos;t lucky, please, contact the developer.</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="100"/>
<source>Could not start http server.</source>
<translation>Could not start http server.</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="144"/>
<source>Selected image: </source>
<translation>Selected image: </translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="204"/>
<source>Captcha was not solved correctly!</source> <source>Captcha was not solved correctly!</source>
<translation>Captcha was not solved correctly!</translation> <translation>Captcha was not solved correctly!</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="87"/> <location filename="../mainwindow.cpp" line="206"/>
<source>Captcha is incorrect</source> <source>Captcha is incorrect</source>
<translation>Captcha is incorrect</translation> <translation>Captcha is incorrect</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="92"/> <location filename="../mainwindow.cpp" line="211"/>
<source>Internal server error. Please, try again later.</source> <source>Internal server error. Please, try again later.</source>
<translation>Internal server error. Please, try again later.</translation> <translation>Internal server error. Please, try again later.</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="94"/> <location filename="../mainwindow.cpp" line="213"/>
<source>Internal server error</source> <source>Internal server error</source>
<translation>Internal server error</translation> <translation>Internal server error</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="99"/> <location filename="../mainwindow.cpp" line="218"/>
<source>Check not found. Please, ensure correctness of entered data.</source> <source>Check not found. Please, ensure correctness of entered data.</source>
<translation>Check not found. Please, ensure correctness of entered data.</translation> <translation>Check not found. Please, ensure correctness of entered data.</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="101"/> <location filename="../mainwindow.cpp" line="220"/>
<source>Check was not found</source> <source>Check was not found</source>
<translation></translation> <translation>Check was not found</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="123"/>
<source>An error has occured. Check was matched incorrectly. Vector sizes are different. Please, contact the developer.</source> <source>An error has occured. Check was matched incorrectly. Vector sizes are different. Please, contact the developer.</source>
<translation>An error has occured. Check was matched incorrectly. Vector sizes are different. Please, contact the developer.</translation> <translation type="vanished">An error has occured. Check was matched incorrectly. Vector sizes are different. Please, contact the developer.</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="125"/>
<source>Error in parsing</source> <source>Error in parsing</source>
<translation>Error in parsing</translation> <translation type="vanished">Error in parsing</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="156"/> <location filename="../mainwindow.cpp" line="137"/>
<source>Please, select a picture where QR code that contains info about check is present</source> <source>Please, select a picture where QR code that contains info about check is present</source>
<translation>Please, select a picture where QR code that contains info about check is present</translation> <translation>Please, select a picture where QR code that contains info about check is present</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="158"/> <location filename="../mainwindow.cpp" line="139"/>
<location filename="../mainwindow.cpp" line="204"/>
<source>Picture was not selected</source> <source>Picture was not selected</source>
<translation>Picture was not selected</translation> <translation>Picture was not selected</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="202"/>
<source>Please, select a picture to scan</source> <source>Please, select a picture to scan</source>
<translation>Please, select a picture to scan</translation> <translation type="vanished">Please, select a picture to scan</translation>
</message>
<message>
<location filename="../scenes/mainwindow.ui" line="26"/>
<source>Form</source>
<translation>Form</translation>
</message>
<message>
<source>Optical Character Recognition</source>
<translation type="vanished">Optical Character Recognition</translation>
</message>
<message>
<source>Text from E-Mail</source>
<translation type="vanished">Text from E-Mail</translation>
</message>
</context>
<context>
<name>OCRScene</name>
<message>
<source>Form</source>
<translation type="vanished">Form</translation>
</message>
<message>
<source>Choose</source>
<translation type="vanished">Choose</translation>
</message>
<message>
<source>Path to image:</source>
<translation type="vanished">Path to image:</translation>
</message>
<message>
<source>Store:</source>
<translation type="vanished">Store:</translation>
</message>
<message>
<source>Recognized text will be shown below as soon as image will be processed. Please, edit it</source>
<translation type="vanished">Recognized text will be shown below as soon as image will be processed. Please, edit it</translation>
</message>
<message>
<source>Back</source>
<translation type="vanished">Back</translation>
</message>
<message>
<source>Parse</source>
<translation type="vanished">Parse</translation>
</message>
<message>
<source>An error has occured. Check was matched incorrectly. Vector sizes are different. Please, contact the developer.</source>
<translation type="vanished">An error has occured. Check was matched incorrectly. Vector sizes are different. Please, contact the developer.</translation>
</message>
<message>
<source>Error in parsing</source>
<translation type="vanished">Error in parsing</translation>
</message>
<message>
<source>Please, select a picture to scan</source>
<translation type="vanished">Please, select a picture to scan</translation>
</message>
<message>
<source>Picture was not selected</source>
<translation type="vanished">Picture was not selected</translation>
</message>
<message>
<source>Path to image: </source>
<translation type="vanished">Path to image: </translation>
</message>
</context>
<context>
<name>OFDScene</name>
<message>
<source>Form</source>
<translation type="vanished">Form</translation>
</message>
<message>
<source>Total</source>
<translation type="vanished">Total</translation>
</message>
<message>
<source>Back</source>
<translation type="vanished">Back</translation>
</message>
<message>
<source>or</source>
<translation type="vanished">or</translation>
</message>
<message>
<source>FD (Fiscal Document)</source>
<translation type="vanished">FD (Fiscal Document)</translation>
</message>
<message>
<source>Date and time of purchase</source>
<translation type="vanished">Date and time of purchase</translation>
</message>
<message>
<source>Stop server</source>
<translation type="vanished">Stop server</translation>
</message>
<message>
<source>Funds income</source>
<translation type="vanished">Funds income</translation>
</message>
<message>
<source>Funds return</source>
<translation type="vanished">Funds return</translation>
</message>
<message>
<source>Funds spend</source>
<translation type="vanished">Funds spend</translation>
</message>
<message>
<source>Spends return</source>
<translation type="vanished">Spends return</translation>
</message>
<message>
<source>Use your phone as a QR code scanner</source>
<translation type="vanished">Use your phone as a QR code scanner</translation>
</message>
<message>
<source>FN (Fiscal Number)</source>
<translation type="vanished">FN (Fiscal Number)</translation>
</message>
<message>
<source>FI (Fiscal Identifier)</source>
<translation type="vanished">FI (Fiscal Identifier)</translation>
</message>
<message>
<source>Choose image on your PC</source>
<translation type="vanished">Choose image on your PC</translation>
</message>
<message>
<source>Operation type</source>
<translation type="vanished">Operation type</translation>
</message>
<message>
<source>Parse</source>
<translation type="vanished">Parse</translation>
</message>
<message>
<source>Could not start http server. 10 times in a row random port was occupied. Either you should run for a lottery ticket, or the problem is in the program. If the lottery ticket wasn&apos;t lucky, please, contact the developer.</source>
<translation type="vanished">Could not start http server. 10 times in a row random port was occupied. Either you should run for a lottery ticket, or the problem is in the program. If the lottery ticket wasn&apos;t lucky, please, contact the developer.</translation>
</message>
<message>
<source>Could not start http server.</source>
<translation type="vanished">Could not start http server.</translation>
</message>
<message>
<source>Please, select a picture where QR code that contains info about check is present</source>
<translation type="vanished">Please, select a picture where QR code that contains info about check is present</translation>
</message>
<message>
<source>Picture was not selected</source>
<translation type="vanished">Picture was not selected</translation>
</message>
<message>
<source>Selected image: </source>
<translation type="vanished">Selected image: </translation>
</message>
<message>
<source>Captcha was not solved correctly!</source>
<translation type="vanished">Captcha was not solved correctly!</translation>
</message>
<message>
<source>Captcha is incorrect</source>
<translation type="vanished">Captcha is incorrect</translation>
</message>
<message>
<source>Internal server error. Please, try again later.</source>
<translation type="vanished">Internal server error. Please, try again later.</translation>
</message>
<message>
<source>Internal server error</source>
<translation type="vanished">Internal server error</translation>
</message>
<message>
<source>Check not found. Please, ensure correctness of entered data.</source>
<translation type="vanished">Check not found. Please, ensure correctness of entered data.</translation>
</message>
<message>
<source>Check was not found</source>
<translation type="vanished">Check was not found</translation>
</message>
<message>
<source>QR code for binaryeye to connect</source>
<translation type="vanished">QR code for binaryeye to connect</translation>
</message>
<message>
<source>I&apos;ve scanned</source>
<translation type="vanished">I&apos;ve scanned</translation>
</message>
<message>
<source>123 123</source>
<translation type="obsolete">123 123</translation>
</message> </message>
</context> </context>
<context> <context>
<name>OutputDialog</name> <name>OutputDialog</name>
<message> <message>
<location filename="../outputdialog.ui" line="14"/> <location filename="../scenes/outputdialog.ui" line="14"/>
<source>Dialog</source> <source>Dialog</source>
<translation>Dialog</translation> <translation>Dialog</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="42"/> <location filename="../scenes/outputdialog.ui" line="20"/>
<source>Path to export: </source> <source>Path to export: </source>
<translation>Path to export: </translation> <translation>Path to export: </translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="55"/> <location filename="../scenes/outputdialog.ui" line="27"/>
<source>Choose</source> <source>Choose</source>
<translation>Choose</translation> <translation>Choose</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="68"/> <location filename="../scenes/outputdialog.ui" line="34"/>
<source>Print header</source> <source>Print header</source>
<translation>Print header</translation> <translation>Print header</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="82"/> <location filename="../scenes/outputdialog.ui" line="55"/>
<source>Goods name</source> <source>Goods name</source>
<translation>Goods name</translation> <translation>Goods name</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="87"/> <location filename="../scenes/outputdialog.ui" line="60"/>
<source>Goods price</source> <source>Goods price</source>
<translation>Goods price</translation> <translation>Goods price</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="92"/> <location filename="../scenes/outputdialog.ui" line="65"/>
<source>Goods quantity</source> <source>Goods quantity</source>
<translation>Goods quality</translation> <translation>Goods quality</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="97"/> <location filename="../scenes/outputdialog.ui" line="70"/>
<source>Goods net weight</source> <source>Goods net weight</source>
<translation>Goods net weight</translation> <translation>Goods net weight</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="102"/> <location filename="../scenes/outputdialog.ui" line="75"/>
<source>Goods total</source> <source>Goods total</source>
<translation>Goods total</translation> <translation>Goods total</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="107"/> <location filename="../scenes/outputdialog.ui" line="80"/>
<source>position</source> <source>position</source>
<translation>position</translation> <translation>position</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="112"/> <location filename="../scenes/outputdialog.ui" line="85"/>
<source>name</source> <source>name</source>
<translation>name</translation> <translation>name</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="117"/> <location filename="../scenes/outputdialog.ui" line="90"/>
<source>1</source> <source>1</source>
<translation>1</translation> <translation>1</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="122"/> <location filename="../scenes/outputdialog.ui" line="95"/>
<source>Name</source> <source>Name</source>
<translation>Name</translation> <translation>Name</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="127"/> <location filename="../scenes/outputdialog.ui" line="100"/>
<source>2</source> <source>2</source>
<translation>2</translation> <translation>2</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="132"/> <location filename="../scenes/outputdialog.ui" line="105"/>
<source>Price</source> <source>Price</source>
<translation>Price</translation> <translation>Price</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="137"/> <location filename="../scenes/outputdialog.ui" line="110"/>
<source>3</source> <source>3</source>
<translation>3</translation> <translation>3</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="142"/> <location filename="../scenes/outputdialog.ui" line="115"/>
<source>Quantity</source> <source>Quantity</source>
<translation>Quantity</translation> <translation>Quantity</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="147"/> <location filename="../scenes/outputdialog.ui" line="120"/>
<source>4</source> <source>4</source>
<translation>4</translation> <translation>4</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="152"/> <location filename="../scenes/outputdialog.ui" line="125"/>
<source>Net weight</source> <source>Net weight</source>
<translation>Net Weight</translation> <translation>Net Weight</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="157"/> <location filename="../scenes/outputdialog.ui" line="130"/>
<source>5</source> <source>5</source>
<translation>5</translation> <translation>5</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="162"/> <location filename="../scenes/outputdialog.ui" line="135"/>
<source>Total price</source> <source>Total price</source>
<translation>Total price</translation> <translation>Total price</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="176"/> <location filename="../scenes/outputdialog.ui" line="41"/>
<source>Print total</source> <source>Print total</source>
<translation>Print total</translation> <translation>Print total</translation>
</message> </message>
</context> </context>
<context>
<name>QObject</name>
<message>
<location filename="../main.cpp" line="60"/>
<source>Using locale: </source>
<translation>Using locale: </translation>
</message>
</context>
<context> <context>
<name>SettingsDialog</name> <name>SettingsDialog</name>
<message> <message>
<location filename="../settingsdialog.cpp" line="149"/> <location filename="../settingsdialog.cpp" line="133"/>
<source>You need to restart program to apply language changes</source> <source>You need to restart program to apply language changes</source>
<translation>You need to restart program to apply language changes</translation> <translation>You need to restart program to apply language changes</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.cpp" line="151"/> <location filename="../settingsdialog.cpp" line="135"/>
<source>Restart required</source> <source>Restart required</source>
<translation>Restart required</translation> <translation>Restart required</translation>
</message> </message>
@ -334,17 +618,17 @@
<context> <context>
<name>SolveCaptchaDialog</name> <name>SolveCaptchaDialog</name>
<message> <message>
<location filename="../solvecaptchadialog.ui" line="14"/> <location filename="../scenes/solvecaptchadialog.ui" line="14"/>
<source>Dialog</source> <source>Dialog</source>
<translation>Dialog</translation> <translation>Dialog</translation>
</message> </message>
<message> <message>
<location filename="../solvecaptchadialog.cpp" line="23"/> <location filename="../solvecaptchadialog.cpp" line="22"/>
<source>Please, enter a valid captcha</source> <source>Please, enter a valid captcha</source>
<translation>Please, enter a valid captcha</translation> <translation>Please, enter a valid captcha</translation>
</message> </message>
<message> <message>
<location filename="../solvecaptchadialog.cpp" line="25"/> <location filename="../solvecaptchadialog.cpp" line="24"/>
<source>No captcha</source> <source>No captcha</source>
<translation>No captcha</translation> <translation>No captcha</translation>
</message> </message>
@ -352,108 +636,106 @@
<context> <context>
<name>settingsdialog</name> <name>settingsdialog</name>
<message> <message>
<location filename="../settingsdialog.ui" line="14"/> <location filename="../scenes/settingsdialog.ui" line="14"/>
<source>Dialog</source> <source>Dialog</source>
<translation>Dialog</translation> <translation>Dialog</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="182"/> <location filename="../scenes/settingsdialog.ui" line="155"/>
<source>Goods name position</source> <source>Goods name position</source>
<translation>Goods name position</translation> <translation>Goods name position</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="234"/> <location filename="../scenes/settingsdialog.ui" line="64"/>
<source>Goods price per unit alias</source> <source>Goods price per unit alias</source>
<translation>Goods price per unit alias</translation> <translation>Goods price per unit alias</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="248"/> <location filename="../scenes/settingsdialog.ui" line="50"/>
<source>TextLabel</source> <source>Language</source>
<translation>Language</translation> <translation>Language</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="256"/> <source>TextLabel</source>
<translation type="vanished">Language</translation>
</message>
<message>
<location filename="../scenes/settingsdialog.ui" line="132"/>
<source>en_US</source> <source>en_US</source>
<translation>en_US</translation> <translation>en_US</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="261"/> <location filename="../scenes/settingsdialog.ui" line="137"/>
<source>ru_RU</source> <source>ru_RU</source>
<translation>ru_RU</translation> <translation>ru_RU</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="224"/>
<location filename="../settingsdialog.ui" line="241"/>
<source>Choose</source> <source>Choose</source>
<translation>Choose</translation> <translation type="vanished">Choose</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="107"/> <location filename="../scenes/settingsdialog.ui" line="104"/>
<source>Print header</source> <source>Print header</source>
<translation>Print header</translation> <translation>Print header</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="150"/> <location filename="../scenes/settingsdialog.ui" line="57"/>
<source>Goods net weight alias</source> <source>Goods net weight alias</source>
<translation>Goods net weight alias</translation> <translation>Goods net weight alias</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="83"/>
<source>Stores modules url</source> <source>Stores modules url</source>
<translation>Stores modules url</translation> <translation type="vanished">Stores modules url</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="163"/> <location filename="../scenes/settingsdialog.ui" line="97"/>
<source>Goods total alias</source> <source>Goods total alias</source>
<translation>Goods total alias</translation> <translation>Goods total alias</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="196"/> <location filename="../scenes/settingsdialog.ui" line="81"/>
<source>Goods name alias</source> <source>Goods name alias</source>
<translation>Goods name alias</translation> <translation>Goods name alias</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="120"/> <location filename="../scenes/settingsdialog.ui" line="37"/>
<source>Goods quantity alias</source> <source>Goods quantity alias</source>
<translation>Goods quantity alias</translation> <translation>Goods quantity alias</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="210"/>
<source>Stores modules directory</source> <source>Stores modules directory</source>
<translation>Stores modules directory</translation> <translation type="vanished">Stores modules directory</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="127"/>
<source>OFD modules directory</source> <source>OFD modules directory</source>
<translation>OFD modules directory</translation> <translation type="vanished">OFD modules directory</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="203"/> <location filename="../scenes/settingsdialog.ui" line="169"/>
<source>Goods price per unit position</source> <source>Goods price per unit position</source>
<translation>Goods price per unit position</translation> <translation>Goods price per unit position</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="73"/> <location filename="../scenes/settingsdialog.ui" line="124"/>
<source>Goods net weight position</source> <source>Goods net weight position</source>
<translation>Goods net weight position</translation> <translation>Goods net weight position</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="100"/>
<source>OFD modules url</source> <source>OFD modules url</source>
<translation>OFD modules url</translation> <translation type="vanished">OFD modules url</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="217"/> <location filename="../scenes/settingsdialog.ui" line="114"/>
<source>Goods total position</source> <source>Goods total position</source>
<translation>Goods total position</translation> <translation>Goods total position</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="90"/> <location filename="../scenes/settingsdialog.ui" line="145"/>
<source>Goods quantity position</source> <source>Goods quantity position</source>
<translation>Goods quantity position</translation> <translation>Goods quantity position</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="137"/> <location filename="../scenes/settingsdialog.ui" line="74"/>
<source>Print total</source> <source>Print total</source>
<translation>Print total</translation> <translation>Print total</translation>
</message> </message>

View File

@ -4,12 +4,12 @@
<context> <context>
<name>AdjustPictureDialog</name> <name>AdjustPictureDialog</name>
<message> <message>
<location filename="../adjustpicturedialog.ui" line="14"/> <location filename="../scenes/adjustpicturedialog.ui" line="14"/>
<source>Dialog</source> <source>Dialog</source>
<translation>Диалог</translation> <translation>Диалог</translation>
</message> </message>
<message> <message>
<location filename="../adjustpicturedialog.ui" line="58"/> <location filename="../scenes/adjustpicturedialog.ui" line="33"/>
<source>Please, zoom to qr code and adjust contrast so that qr code looks sharp</source> <source>Please, zoom to qr code and adjust contrast so that qr code looks sharp</source>
<translation>Пожалуйста, приблизьте QR код и настройте контраст, чтобы он читался</translation> <translation>Пожалуйста, приблизьте QR код и настройте контраст, чтобы он читался</translation>
</message> </message>
@ -24,305 +24,589 @@
<translation>QR код не найден</translation> <translation>QR код не найден</translation>
</message> </message>
</context> </context>
<context>
<name>EmailTextScene</name>
<message>
<source>Form</source>
<translation type="vanished">Форма</translation>
</message>
<message>
<source>Store type</source>
<translation type="obsolete">Магазин</translation>
</message>
<message>
<source>Check content</source>
<translation type="vanished">Контент чека</translation>
</message>
<message>
<source>Parse</source>
<translation type="vanished">Парсить</translation>
</message>
<message>
<source>Store:</source>
<translation type="vanished">Магазин:</translation>
</message>
<message>
<source>Back</source>
<translation type="vanished">Назад</translation>
</message>
<message>
<source>An error has occured. Check was matched incorrectly. Vector sizes are different. Please, contact the developer.</source>
<translation type="vanished">Произошла ошибка. Чек был прочитан неверно. Размеры векторов различаются. Пожалуйста, сообщите об этом разработчику.</translation>
</message>
<message>
<source>Error in parsing</source>
<translation type="vanished">Ошибка в парсинге</translation>
</message>
</context>
<context> <context>
<name>MainWindow</name> <name>MainWindow</name>
<message> <message>
<location filename="../mainwindow.ui" line="14"/>
<source>MainWindow</source> <source>MainWindow</source>
<translation>ГлавноеОкно</translation> <translation type="vanished">ГлавноеОкно</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="37"/>
<source>Store type</source> <source>Store type</source>
<translation>Магазин</translation> <translation type="vanished">Магазин</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="50"/> <location filename="../scenes/mainwindow.ui" line="51"/>
<source>Parse</source> <source>Parse</source>
<translation>Парсить</translation> <translation>Парсить</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="63"/>
<source>Preferences</source> <source>Preferences</source>
<translation>Настройки</translation> <translation type="vanished">Настройки</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="80"/>
<source>Text</source> <source>Text</source>
<translation>Текст</translation> <translation type="vanished">Текст</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="92"/>
<source>Check content</source> <source>Check content</source>
<translation>Контент чека</translation> <translation type="vanished">Контент чека</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="108"/>
<source>OCR</source> <source>OCR</source>
<translatorcomment>Оптическое Распознавание Символов</translatorcomment> <translatorcomment>Оптическое Распознавание Символов</translatorcomment>
<translation>ОРС</translation> <translation type="vanished">ОРС</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="120"/>
<location filename="../mainwindow.ui" line="213"/>
<source>Choose</source> <source>Choose</source>
<translation>Выбрать</translation> <translation type="vanished">Выбрать</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="143"/>
<location filename="../mainwindow.ui" line="200"/>
<source>Path to image: </source> <source>Path to image: </source>
<translation>Путь к изображению: </translation> <translation type="vanished">Путь к изображению: </translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="156"/>
<source>Here is recognised check text. Please, edit it if something&apos;s wrong:</source> <source>Here is recognised check text. Please, edit it if something&apos;s wrong:</source>
<translation>Ниже приведён распознанный текст. Пожалуйста, отредактируйте его:</translation> <translation type="vanished">Ниже приведён распознанный текст. Пожалуйста, отредактируйте его:</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="175"/>
<source>OFD</source> <source>OFD</source>
<translatorcomment>Оператор Фискальных Данных</translatorcomment> <translatorcomment>Оператор Фискальных Данных</translatorcomment>
<translation>ОФД</translation> <translation type="vanished">ОФД</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="226"/>
<source>0000000000000000</source> <source>0000000000000000</source>
<translation>0000000000000000</translation> <translation type="vanished">0000000000000000</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="245"/> <location filename="../scenes/mainwindow.ui" line="77"/>
<source>FN (Fiscal Number)</source> <source>FN (Fiscal Number)</source>
<translatorcomment>Фискальный Норма</translatorcomment> <translatorcomment>Фискальный Норма</translatorcomment>
<translation>ФН</translation> <translation>ФН</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="264"/> <location filename="../scenes/mainwindow.ui" line="64"/>
<source>FD (Fiscal Document)</source> <source>FD (Fiscal Document)</source>
<translatorcomment>Фискальный Документ</translatorcomment> <translatorcomment>Фискальный Документ</translatorcomment>
<translation>ФД</translation> <translation>ФД</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="277"/>
<location filename="../mainwindow.ui" line="309"/>
<source>0000000000</source> <source>0000000000</source>
<translation>000000000</translation> <translation type="vanished">000000000</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="296"/> <source>Back</source>
<translation type="obsolete">Назад</translation>
</message>
<message>
<location filename="../scenes/mainwindow.ui" line="130"/>
<source>Stop server</source>
<translation>Остановить сервер</translation>
</message>
<message>
<location filename="../scenes/mainwindow.ui" line="143"/>
<source>Choose image on your PC</source>
<translation>Выбрать изображение на компьютере</translation>
</message>
<message>
<location filename="../scenes/mainwindow.ui" line="38"/>
<location filename="../scenes/mainwindow.ui" line="183"/>
<source>or</source>
<translation>или</translation>
</message>
<message>
<location filename="../scenes/mainwindow.ui" line="97"/>
<source>Use your phone as a QR code scanner</source>
<translation>Использовать телефон как сканнер QR</translation>
</message>
<message>
<location filename="../scenes/mainwindow.ui" line="157"/>
<source>FI (Fiscal Identifier)</source> <source>FI (Fiscal Identifier)</source>
<translatorcomment>Фискальный Признак</translatorcomment> <translatorcomment>Фискальный Признак</translatorcomment>
<translation>ФП</translation> <translation>ФП</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="333"/> <location filename="../scenes/mainwindow.ui" line="117"/>
<source>Date and time of purchase</source>
<translation>Дата и время покупки</translation>
</message>
<message>
<location filename="../scenes/mainwindow.ui" line="84"/>
<source>Operation type</source>
<translation>Тип операции</translation>
</message>
<message>
<location filename="../scenes/mainwindow.ui" line="170"/>
<source>Parse an E-Mail</source>
<translation>Парсить E-Mail</translation>
</message>
<message>
<location filename="../scenes/mainwindow.ui" line="210"/>
<source>Funds income</source> <source>Funds income</source>
<translation>Приход средств</translation> <translation>Приход средств</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="338"/> <location filename="../scenes/mainwindow.ui" line="215"/>
<source>Funds return</source> <source>Funds return</source>
<translation>Возврат средств</translation> <translation>Возврат средств</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="343"/> <location filename="../scenes/mainwindow.ui" line="220"/>
<source>Funds spend</source> <source>Funds spend</source>
<translation>Расход средств</translation> <translation>Расход средств</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="348"/> <location filename="../scenes/mainwindow.ui" line="225"/>
<source>Spends return</source> <source>Spends return</source>
<translation>Возврат расхода</translation> <translation>Возврат расхода</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="375"/> <location filename="../scenes/mainwindow.ui" line="246"/>
<source>Settings</source>
<translation>Настройки</translation>
</message>
<message>
<location filename="../scenes/mainwindow.ui" line="150"/>
<source>Total</source> <source>Total</source>
<translation>Итого</translation> <translation>Итого</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="392"/>
<source>checks parser</source> <source>checks parser</source>
<translation>Парсер чеков</translation> <translation type="vanished">Парсер чеков</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="85"/> <location filename="../mainwindow.cpp" line="91"/>
<source>QR code for binaryeye to connect</source>
<translation>QR код для подключения BinaryEye</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="92"/>
<source>I&apos;ve scanned</source>
<translation>Просканировал</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="98"/>
<source>Could not start http server. 10 times in a row random port was occupied. Either you should run for a lottery ticket, or the problem is in the program. If the lottery ticket wasn&apos;t lucky, please, contact the developer.</source>
<translation>Не смог поднять HTTP сервер. 10 раз подряд случайно выбранный порт был занят. Либо Вам следует бежать за лоттерейным билетом, или в программе баг. Если лотерейный билет не был выигрышным, пожалуйста, сообщите разработчику.</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="100"/>
<source>Could not start http server.</source>
<translation>Не получилось запустить HTTP сервер.</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="144"/>
<source>Selected image: </source>
<translation>Выбранное изображение: </translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="204"/>
<source>Captcha was not solved correctly!</source> <source>Captcha was not solved correctly!</source>
<translation>Капча была решена неверно!</translation> <translation>Капча была решена неверно!</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="87"/> <location filename="../mainwindow.cpp" line="206"/>
<source>Captcha is incorrect</source> <source>Captcha is incorrect</source>
<translation>Капча введена неверно</translation> <translation>Капча введена неверно</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="92"/> <location filename="../mainwindow.cpp" line="211"/>
<source>Internal server error. Please, try again later.</source> <source>Internal server error. Please, try again later.</source>
<translation>Внутренняя ошибка сервера. Пожалуйста, попробуйте снова позже.</translation> <translation>Внутренняя ошибка сервера. Пожалуйста, попробуйте снова позже.</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="94"/> <location filename="../mainwindow.cpp" line="213"/>
<source>Internal server error</source> <source>Internal server error</source>
<translation>Внутренняя ошибка сервера</translation> <translation>Внутренняя ошибка сервера</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="99"/> <location filename="../mainwindow.cpp" line="218"/>
<source>Check not found. Please, ensure correctness of entered data.</source> <source>Check not found. Please, ensure correctness of entered data.</source>
<translation>Чек не найден. Пожалуйста, убедитесь в правильности введённых данных.</translation> <translation>Чек не найден. Пожалуйста, убедитесь в правильности введённых данных.</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="101"/> <location filename="../mainwindow.cpp" line="220"/>
<source>Check was not found</source> <source>Check was not found</source>
<translation>Чек не найден</translation> <translation>Чек не найден</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="123"/>
<source>An error has occured. Check was matched incorrectly. Vector sizes are different. Please, contact the developer.</source> <source>An error has occured. Check was matched incorrectly. Vector sizes are different. Please, contact the developer.</source>
<translation>Произошла ошибка. Чек был прочитан неверно. Размеры векторов различаются. Пожалуйста, сообщите об этом разработчику.</translation> <translation type="vanished">Произошла ошибка. Чек был прочитан неверно. Размеры векторов различаются. Пожалуйста, сообщите об этом разработчику.</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="125"/>
<source>Error in parsing</source> <source>Error in parsing</source>
<translation>Ошибка в парсинге</translation> <translation type="vanished">Ошибка в парсинге</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="156"/> <location filename="../mainwindow.cpp" line="137"/>
<source>Please, select a picture where QR code that contains info about check is present</source> <source>Please, select a picture where QR code that contains info about check is present</source>
<translation>Пожалуйста, выберете изображение, содержащее QR код с информацией о чеке</translation> <translation>Пожалуйста, выберете изображение, содержащее QR код с информацией о чеке</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="158"/> <location filename="../mainwindow.cpp" line="139"/>
<location filename="../mainwindow.cpp" line="204"/>
<source>Picture was not selected</source> <source>Picture was not selected</source>
<translation>Изображение не было выбрано</translation> <translation>Изображение не было выбрано</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="202"/>
<source>Please, select a picture to scan</source> <source>Please, select a picture to scan</source>
<translation>Пожалуйста, выберете изображение для сканирования</translation> <translation type="vanished">Пожалуйста, выберете изображение для сканирования</translation>
</message>
<message>
<location filename="../scenes/mainwindow.ui" line="26"/>
<source>Form</source>
<translation>Форма</translation>
</message>
<message>
<source>Optical Character Recognition</source>
<translation type="vanished">Оптическое распознавание символов</translation>
</message>
<message>
<source>Text from E-Mail</source>
<translation type="vanished">Текст из электронного письма</translation>
</message>
</context>
<context>
<name>OCRScene</name>
<message>
<source>Form</source>
<translation type="vanished">Форма</translation>
</message>
<message>
<source>Choose</source>
<translation type="vanished">Выбрать</translation>
</message>
<message>
<source>Path to image:</source>
<translation type="vanished">Путь к изображению:</translation>
</message>
<message>
<source>Store:</source>
<translation type="vanished">Магазин:</translation>
</message>
<message>
<source>Recognized text will be shown below as soon as image will be processed. Please, edit it</source>
<translation type="vanished">Распознанный текст будет показан ниже как только изображение обработается. Пожалуйста, отредактируйте</translation>
</message>
<message>
<source>Back</source>
<translation type="vanished">Назад</translation>
</message>
<message>
<source>Parse</source>
<translation type="vanished">Парсить</translation>
</message>
<message>
<source>An error has occured. Check was matched incorrectly. Vector sizes are different. Please, contact the developer.</source>
<translation type="vanished">Произошла ошибка. Чек был прочитан неверно. Размеры векторов различаются. Пожалуйста, сообщите об этом разработчику.</translation>
</message>
<message>
<source>Error in parsing</source>
<translation type="vanished">Ошибка в парсинге</translation>
</message>
<message>
<source>Please, select a picture to scan</source>
<translation type="vanished">Пожалуйста, выберете изображение для сканирования</translation>
</message>
<message>
<source>Picture was not selected</source>
<translation type="vanished">Изображение не было выбрано</translation>
</message>
<message>
<source>Path to image: </source>
<translation type="vanished">Путь к изображению: </translation>
</message>
</context>
<context>
<name>OFDScene</name>
<message>
<source>Form</source>
<translation type="vanished">Форма</translation>
</message>
<message>
<source>Total</source>
<translation type="vanished">Итого</translation>
</message>
<message>
<source>Back</source>
<translation type="vanished">Назад</translation>
</message>
<message>
<source>or</source>
<translation type="vanished">или</translation>
</message>
<message>
<source>FD (Fiscal Document)</source>
<translation type="vanished">ФД</translation>
</message>
<message>
<source>Date and time of purchase</source>
<translation type="vanished">Дата и время покупки</translation>
</message>
<message>
<source>Stop server</source>
<translation type="vanished">Остановить сервер</translation>
</message>
<message>
<source>Funds income</source>
<translation type="vanished">Приход средств</translation>
</message>
<message>
<source>Funds return</source>
<translation type="vanished">Возврат средств</translation>
</message>
<message>
<source>Funds spend</source>
<translation type="vanished">Расход средств</translation>
</message>
<message>
<source>Spends return</source>
<translation type="vanished">Возврат расхода</translation>
</message>
<message>
<source>Use your phone as a QR code scanner</source>
<translation type="vanished">Использовать телефон как сканнер QR</translation>
</message>
<message>
<source>FN (Fiscal Number)</source>
<translation type="vanished">ФН</translation>
</message>
<message>
<source>FI (Fiscal Identifier)</source>
<translation type="vanished">ФП</translation>
</message>
<message>
<source>Choose image on your PC</source>
<translation type="vanished">Выбрать изображение на компьютере</translation>
</message>
<message>
<source>Operation type</source>
<translation type="vanished">Тип операции</translation>
</message>
<message>
<source>Parse</source>
<translation type="vanished">Парсить</translation>
</message>
<message>
<source>Could not start http server. 10 times in a row random port was occupied. Either you should run for a lottery ticket, or the problem is in the program. If the lottery ticket wasn&apos;t lucky, please, contact the developer.</source>
<translation type="vanished">Не смог поднять HTTP сервер. 10 раз подряд случайно выбранный порт был занят. Либо Вам следует бежать за лоттерейным билетом, или в программе баг. Если лотерейный билет не был выигрышным, пожалуйста, сообщите разработчику.</translation>
</message>
<message>
<source>Could not start http server.</source>
<translation type="vanished">Не получилось запустить HTTP сервер.</translation>
</message>
<message>
<source>Please, select a picture where QR code that contains info about check is present</source>
<translation type="vanished">Пожалуйста, выберете изображение, содержащее QR код с информацией о чеке</translation>
</message>
<message>
<source>Picture was not selected</source>
<translation type="vanished">Изображение не было выбрано</translation>
</message>
<message>
<source>Selected image: </source>
<translation type="vanished">Выбранное изображение: </translation>
</message>
<message>
<source>Captcha was not solved correctly!</source>
<translation type="vanished">Капча была решена неверно!</translation>
</message>
<message>
<source>Captcha is incorrect</source>
<translation type="vanished">Капча введена неверно</translation>
</message>
<message>
<source>Internal server error. Please, try again later.</source>
<translation type="vanished">Внутренняя ошибка сервера. Пожалуйста, попробуйте снова позже.</translation>
</message>
<message>
<source>Internal server error</source>
<translation type="vanished">Внутренняя ошибка сервера</translation>
</message>
<message>
<source>Check not found. Please, ensure correctness of entered data.</source>
<translation type="vanished">Чек не найден. Пожалуйста, убедитесь в правильности введённых данных.</translation>
</message>
<message>
<source>Check was not found</source>
<translation type="vanished">Чек не найден</translation>
</message>
<message>
<source>QR code for binaryeye to connect</source>
<translation type="vanished">QR код для подключения BinaryEye</translation>
</message>
<message>
<source>I&apos;ve scanned</source>
<translation type="vanished">Просканировал</translation>
</message>
<message>
<source>123 123</source>
<translation type="obsolete">123 123</translation>
</message> </message>
</context> </context>
<context> <context>
<name>OutputDialog</name> <name>OutputDialog</name>
<message> <message>
<location filename="../outputdialog.ui" line="14"/> <location filename="../scenes/outputdialog.ui" line="14"/>
<source>Dialog</source> <source>Dialog</source>
<translation>Диалог</translation> <translation>Диалог</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="42"/> <location filename="../scenes/outputdialog.ui" line="20"/>
<source>Path to export: </source> <source>Path to export: </source>
<translation>Путь для экспорта: </translation> <translation>Путь для экспорта: </translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="55"/> <location filename="../scenes/outputdialog.ui" line="27"/>
<source>Choose</source> <source>Choose</source>
<translation>Выбрать</translation> <translation>Выбрать</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="68"/> <location filename="../scenes/outputdialog.ui" line="34"/>
<source>Print header</source> <source>Print header</source>
<translation>Печатать заголовок</translation> <translation>Печатать заголовок</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="82"/> <location filename="../scenes/outputdialog.ui" line="55"/>
<source>Goods name</source> <source>Goods name</source>
<translation>Имя товара</translation> <translation>Имя товара</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="87"/> <location filename="../scenes/outputdialog.ui" line="60"/>
<source>Goods price</source> <source>Goods price</source>
<translation>Цена товара</translation> <translation>Цена товара</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="92"/> <location filename="../scenes/outputdialog.ui" line="65"/>
<source>Goods quantity</source> <source>Goods quantity</source>
<translation>Количество товара</translation> <translation>Количество товара</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="97"/> <location filename="../scenes/outputdialog.ui" line="70"/>
<source>Goods net weight</source> <source>Goods net weight</source>
<translation>Масса нетто товара</translation> <translation>Масса нетто товара</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="102"/> <location filename="../scenes/outputdialog.ui" line="75"/>
<source>Goods total</source> <source>Goods total</source>
<translation>Всего за товар</translation> <translation>Всего за товар</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="107"/> <location filename="../scenes/outputdialog.ui" line="80"/>
<source>position</source> <source>position</source>
<translation>позиция</translation> <translation>позиция</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="112"/> <location filename="../scenes/outputdialog.ui" line="85"/>
<source>name</source> <source>name</source>
<translation>алиас</translation> <translation>алиас</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="117"/> <location filename="../scenes/outputdialog.ui" line="90"/>
<source>1</source> <source>1</source>
<translation>1</translation> <translation>1</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="122"/> <location filename="../scenes/outputdialog.ui" line="95"/>
<source>Name</source> <source>Name</source>
<translation>Имя</translation> <translation>Имя</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="127"/> <location filename="../scenes/outputdialog.ui" line="100"/>
<source>2</source> <source>2</source>
<translation>2</translation> <translation>2</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="132"/> <location filename="../scenes/outputdialog.ui" line="105"/>
<source>Price</source> <source>Price</source>
<translation>Цена</translation> <translation>Цена</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="137"/> <location filename="../scenes/outputdialog.ui" line="110"/>
<source>3</source> <source>3</source>
<translation>3</translation> <translation>3</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="142"/> <location filename="../scenes/outputdialog.ui" line="115"/>
<source>Quantity</source> <source>Quantity</source>
<translation>Количество</translation> <translation>Количество</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="147"/> <location filename="../scenes/outputdialog.ui" line="120"/>
<source>4</source> <source>4</source>
<translation>4</translation> <translation>4</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="152"/> <location filename="../scenes/outputdialog.ui" line="125"/>
<source>Net weight</source> <source>Net weight</source>
<translation>Масса нетто</translation> <translation>Масса нетто</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="157"/> <location filename="../scenes/outputdialog.ui" line="130"/>
<source>5</source> <source>5</source>
<translation>5</translation> <translation>5</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="162"/> <location filename="../scenes/outputdialog.ui" line="135"/>
<source>Total price</source> <source>Total price</source>
<translation>Всего</translation> <translation>Всего</translation>
</message> </message>
<message> <message>
<location filename="../outputdialog.ui" line="176"/> <location filename="../scenes/outputdialog.ui" line="41"/>
<source>Print total</source> <source>Print total</source>
<translation>Печатать Итого</translation> <translation>Печатать Итого</translation>
</message> </message>
</context> </context>
<context>
<name>QObject</name>
<message>
<location filename="../main.cpp" line="60"/>
<source>Using locale: </source>
<translation>Использую локаль: </translation>
</message>
</context>
<context> <context>
<name>SettingsDialog</name> <name>SettingsDialog</name>
<message> <message>
<location filename="../settingsdialog.cpp" line="149"/> <location filename="../settingsdialog.cpp" line="133"/>
<source>You need to restart program to apply language changes</source> <source>You need to restart program to apply language changes</source>
<translation>Требуется перезагрузить программу, чтобы применить изменения языка</translation> <translation>Требуется перезагрузить программу, чтобы применить изменения языка</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.cpp" line="151"/> <location filename="../settingsdialog.cpp" line="135"/>
<source>Restart required</source> <source>Restart required</source>
<translation>Требуется перезагрузка</translation> <translation>Требуется перезагрузка</translation>
</message> </message>
@ -330,17 +614,17 @@
<context> <context>
<name>SolveCaptchaDialog</name> <name>SolveCaptchaDialog</name>
<message> <message>
<location filename="../solvecaptchadialog.ui" line="14"/> <location filename="../scenes/solvecaptchadialog.ui" line="14"/>
<source>Dialog</source> <source>Dialog</source>
<translation>Диалог</translation> <translation>Диалог</translation>
</message> </message>
<message> <message>
<location filename="../solvecaptchadialog.cpp" line="23"/> <location filename="../solvecaptchadialog.cpp" line="22"/>
<source>Please, enter a valid captcha</source> <source>Please, enter a valid captcha</source>
<translation>Пожалуйста, введите верную капчу</translation> <translation>Пожалуйста, введите верную капчу</translation>
</message> </message>
<message> <message>
<location filename="../solvecaptchadialog.cpp" line="25"/> <location filename="../solvecaptchadialog.cpp" line="24"/>
<source>No captcha</source> <source>No captcha</source>
<translation>Нет капчи</translation> <translation>Нет капчи</translation>
</message> </message>
@ -348,108 +632,106 @@
<context> <context>
<name>settingsdialog</name> <name>settingsdialog</name>
<message> <message>
<location filename="../settingsdialog.ui" line="14"/> <location filename="../scenes/settingsdialog.ui" line="14"/>
<source>Dialog</source> <source>Dialog</source>
<translation>Диалог</translation> <translation>Диалог</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="182"/> <location filename="../scenes/settingsdialog.ui" line="155"/>
<source>Goods name position</source> <source>Goods name position</source>
<translation>Позиция имени товара</translation> <translation>Позиция имени товара</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="234"/> <location filename="../scenes/settingsdialog.ui" line="64"/>
<source>Goods price per unit alias</source> <source>Goods price per unit alias</source>
<translation>Алиас цены товара</translation> <translation>Алиас цены товара</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="248"/> <location filename="../scenes/settingsdialog.ui" line="50"/>
<source>TextLabel</source> <source>Language</source>
<translation>Язык</translation> <translation>Язык</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="256"/> <source>TextLabel</source>
<translation type="vanished">Язык</translation>
</message>
<message>
<location filename="../scenes/settingsdialog.ui" line="132"/>
<source>en_US</source> <source>en_US</source>
<translation>en_US</translation> <translation>en_US</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="261"/> <location filename="../scenes/settingsdialog.ui" line="137"/>
<source>ru_RU</source> <source>ru_RU</source>
<translation>ru_RU</translation> <translation>ru_RU</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="224"/>
<location filename="../settingsdialog.ui" line="241"/>
<source>Choose</source> <source>Choose</source>
<translation>Выбрать</translation> <translation type="vanished">Выбрать</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="107"/> <location filename="../scenes/settingsdialog.ui" line="104"/>
<source>Print header</source> <source>Print header</source>
<translation>Печатать заголовок</translation> <translation>Печатать заголовок</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="150"/> <location filename="../scenes/settingsdialog.ui" line="57"/>
<source>Goods net weight alias</source> <source>Goods net weight alias</source>
<translation>Алиас массы нетто товара</translation> <translation>Алиас массы нетто товара</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="83"/>
<source>Stores modules url</source> <source>Stores modules url</source>
<translation>URL модулей магазина</translation> <translation type="vanished">URL модулей магазина</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="163"/> <location filename="../scenes/settingsdialog.ui" line="97"/>
<source>Goods total alias</source> <source>Goods total alias</source>
<translation>Алиас всего за продукт</translation> <translation>Алиас всего за продукт</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="196"/> <location filename="../scenes/settingsdialog.ui" line="81"/>
<source>Goods name alias</source> <source>Goods name alias</source>
<translation>Алиас имени товара</translation> <translation>Алиас имени товара</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="120"/> <location filename="../scenes/settingsdialog.ui" line="37"/>
<source>Goods quantity alias</source> <source>Goods quantity alias</source>
<translation>Алиас количества товара</translation> <translation>Алиас количества товара</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="210"/>
<source>Stores modules directory</source> <source>Stores modules directory</source>
<translation>Директория модулей магазина</translation> <translation type="vanished">Директория модулей магазина</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="127"/>
<source>OFD modules directory</source> <source>OFD modules directory</source>
<translation>Директория модулей ОФД</translation> <translation type="vanished">Директория модулей ОФД</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="203"/> <location filename="../scenes/settingsdialog.ui" line="169"/>
<source>Goods price per unit position</source> <source>Goods price per unit position</source>
<translation>Позиция центы товара</translation> <translation>Позиция центы товара</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="73"/> <location filename="../scenes/settingsdialog.ui" line="124"/>
<source>Goods net weight position</source> <source>Goods net weight position</source>
<translation>Позиция массы нетто товара</translation> <translation>Позиция массы нетто товара</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="100"/>
<source>OFD modules url</source> <source>OFD modules url</source>
<translation>URL модулей ОФД</translation> <translation type="vanished">URL модулей ОФД</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="217"/> <location filename="../scenes/settingsdialog.ui" line="114"/>
<source>Goods total position</source> <source>Goods total position</source>
<translation>Позиция всего за товар</translation> <translation>Позиция всего за товар</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="90"/> <location filename="../scenes/settingsdialog.ui" line="145"/>
<source>Goods quantity position</source> <source>Goods quantity position</source>
<translation>Позиция количества товара</translation> <translation>Позиция количества товара</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="137"/> <location filename="../scenes/settingsdialog.ui" line="74"/>
<source>Print total</source> <source>Print total</source>
<translation>Печатать Итого</translation> <translation>Печатать Итого</translation>
</message> </message>

View File

@ -1,12 +1,57 @@
#include "utils.h" #include <utils/utils.h>
#ifdef BUILD_OFD_BINARYEYE_SCAN
# include <arpa/inet.h>
# include <qrencode.h>
# include <ifaddrs.h>
# include <netinet/in.h>
#endif
#ifdef BUILD_OFD_MODE
# include <exceptions/ofdrequestexception.h>
# include <fstream>
#endif
#include <codecvt> #include <codecvt>
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
#include <locale> #include <locale>
#include <regex> #if defined(BUILD_OCR_MODE) || defined(BUILD_OFD_MODE)
# include <opencv2/core/mat.hpp>
# include <opencv2/imgcodecs.hpp>
# include <opencv2/imgproc.hpp>
#endif
#include <string> #include <string>
#include "../exceptions/ofdrequestexception.h" #include <QWidget>
#include <boost/regex.hpp>
#include <net/net.h>
#include <settings/settings.h>
#ifdef BUILD_OFD_BINARYEYE_SCAN
std::string get_local_ip_address() {
struct ifaddrs * ifAddrStruct=NULL;
struct ifaddrs * ifa=NULL;
void * tmpAddrPtr=NULL;
getifaddrs(&ifAddrStruct);
for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == nullptr) continue;
if (ifa->ifa_addr->sa_family==AF_INET) {
tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
char addressBuffer[128];
inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
std::string value(addressBuffer);
if (!strncmp(value.c_str(), "192.168", 7)) {
return value;
}
}
}
if (ifAddrStruct!=NULL)
freeifaddrs(ifAddrStruct);
throw std::runtime_error(QWidget::tr("Could not find any usable local IP address. If you beleive that this is problem with the program, please, contact the developer.").toStdString());
}
#endif
std::string to_utf8(std::wstring wide_string) { std::string to_utf8(std::wstring wide_string) {
static std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8_conv; static std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8_conv;
@ -29,10 +74,17 @@ bool vector_contains_element(const std::vector<T>& vector, const T& to_find) {
} }
return false; return false;
} }
template<class T>
bool areAllSizesEqual(const std::vector<T>& v1, const std::vector<T>& v2,
const std::vector<T>& v3, const std::vector<T>& v4) {
return (v1.size() == v2.size() && v2.size() == v3.size() && v3.size() == v4.size());
}
//ужас //ужас
template bool vector_contains_element<std::string>(const std::vector<std::string>& vector, const std::string& to_find); template bool vector_contains_element<std::string>(const std::vector<std::string>& vector, const std::string& to_find);
template bool areAllSizesEqual(const std::vector<std::string>& v1, const std::vector<std::string>& v2,
const std::vector<std::string>& v3, const std::vector<std::string>& v4);
std::vector<std::string> split(std::string s, std::string delimiter) { std::vector<std::string> split(std::string s, std::string delimiter) {
std::vector<std::string> result; std::vector<std::string> result;
size_t pos = 0; size_t pos = 0;
@ -47,16 +99,30 @@ std::vector<std::string> split(std::string s, std::string delimiter) {
return result; return result;
} }
std::vector<std::wstring> split(std::wstring s, std::wstring delimiter) {
std::vector<std::wstring> result;
size_t pos = 0;
std::wstring token;
while ((pos = s.find(delimiter)) != std::string::npos) {
token = s.substr(0, pos);
result.push_back(token);
s.erase(0, pos + delimiter.length());
}
result.push_back(s);
return result;
}
std::wstring substring_from_to(std::wstring& text, std::wstring from, std::wstring to) { std::wstring substring_from_to(std::wstring& text, std::wstring from, std::wstring to) {
unsigned int start_pos = 0; unsigned int start_pos = 0;
unsigned int end_pos = 0; unsigned int end_pos = 0;
std::wstring substring; std::wstring substring;
std::wregex start_regex(from); boost::wregex start_regex(from);
std::wregex end_regex(to); boost::wregex end_regex(to);
for (std::wsregex_iterator it{text.begin(), text.end(), start_regex}, end{}; for (boost::wsregex_iterator it{text.begin(), text.end(), start_regex}, end{};
it != end; it++) { it != end; it++) {
start_pos = it->position() + it->str().size(); start_pos = it->position() + it->str().size();
break; break;
@ -65,7 +131,7 @@ std::wstring substring_from_to(std::wstring& text, std::wstring from, std::wstri
if(text == from_utf8("")) return text; if(text == from_utf8("")) return text;
substring = text.substr(start_pos, text.size()); substring = text.substr(start_pos, text.size());
for (std::wsregex_iterator it{substring.begin(), substring.end(), end_regex}, end{}; for (boost::wsregex_iterator it{substring.begin(), substring.end(), end_regex}, end{};
it != end; it++) { it != end; it++) {
end_pos = it->position(); end_pos = it->position();
break; break;
@ -77,7 +143,7 @@ std::wstring substring_from_to(std::wstring& text, std::wstring from, std::wstri
return substring; return substring;
} }
#ifdef BUILD_OFD_MODE
std::wstring trim_html_response(std::wstring& check) { std::wstring trim_html_response(std::wstring& check) {
std::wstring begin_check_marker = from_utf8("<!-- Products -->"); std::wstring begin_check_marker = from_utf8("<!-- Products -->");
std::wstring end_check_marker = from_utf8("<!-- \\/Products -->"); std::wstring end_check_marker = from_utf8("<!-- \\/Products -->");
@ -87,30 +153,91 @@ std::wstring trim_html_response(std::wstring& check) {
} }
std::vector<std::wstring> find_in_html(std::string& html, std::string regex, std::string html_start, std::string html_end) { std::vector<std::wstring> find_in_html(std::string& html, std::string regex, std::string html_start, std::string html_end) {
std::regex searching_regex(regex); boost::regex searching_regex(regex);
std::vector<std::wstring> parsed; std::vector<std::wstring> parsed;
for (std::sregex_iterator it{html.begin(), html.end(), searching_regex}, end{}; for (boost::sregex_iterator it{html.begin(), html.end(), searching_regex}, end{};
it != end; it++) { it != end; it++) {
std::wstring found_entry = from_utf8(it->str()); std::wstring found_entry = from_utf8(it->str());
std::cout << "Found: " << to_utf8(found_entry) << std::endl;
std::wstring extracted = substring_from_to(found_entry, from_utf8(html_start), from_utf8(html_end)); std::wstring extracted = substring_from_to(found_entry, from_utf8(html_start), from_utf8(html_end));
std::cout << "Extracted: " << to_utf8(extracted) << std::endl;
parsed.push_back(extracted); parsed.push_back(extracted);
} }
return parsed; return parsed;
} }
std::vector<std::wstring> find_products_in_html(std::string html) { std::vector<std::wstring> find_products_in_html(std::string html) {
return find_in_html(html, "<div class=\"ifw-col ifw-col-1 text-left\"><b>.*<\\/b><\\/div>", "<div class=\"ifw-col ifw-col-1 text-left\"><b>", "<\\/b><\\/div>"); return find_in_html(html, "<div class=\"ifw-col ifw-col-1 text-left\"><b>.{2,100}<\\/b><\\/div>", "<div class=\"ifw-col ifw-col-1 text-left\"><b>", "<\\/b><\\/div>");
} }
std::vector<std::wstring> find_amounts_in_html(std::string html) { std::vector<std::wstring> find_amounts_in_html(std::string html) {
return find_in_html(html, "<span>\\d+<\\/span>", "<span>", "<\\/span>"); std::vector<std::wstring> founds = find_in_html(html, "<div><span>\\d+(\\.|\\,)?\\d{0,3}<\\/span>", "<span>", "<\\/span>");
for (auto &found : founds) {
std::replace(found.begin(), found.end(), ',', '.');
}
return founds;
}
std::vector<std::wstring> find_net_weights_in_names(std::vector<std::wstring> &names) {
std::vector<std::wstring> result;
for (std::wstring &name : names ) {
boost::wregex regexp(from_utf8("((\\d+(\\.|,)?\\d{0,}((м|)л|(к|м|)г|т|ц|шт|(pc|)s|(m|k|)g|(m|)l|t))(\\s|\\t){0,})+"), boost::regex_constants::collate);
bool found = false;
for (boost::wsregex_iterator it{name.begin(), name.end(), regexp}, end{}; it != end;
it++) {
result.push_back(it->str());
found = true;
name.erase(it->position(), it->str().length());
break;
}
if (!found) {
result.push_back(from_utf8("?"));
}
}
for (auto &entry : result) {
std::replace(entry.begin(), entry.end(), ',', '.');
}
return result;
} }
std::vector<std::wstring> find_prices_in_html(std::string html) { std::vector<std::wstring> find_prices_in_html(std::string html) {
return find_in_html(html, "X <\\/span><span>\\d+\\.\\d{2}<\\/span>", "X <\\/span><span>", "<\\/span>"); std::vector<std::wstring> founds = find_in_html(html, "X <\\/span><span>\\d+(\\.|,)\\d{2}<\\/span>", "X <\\/span><span>", "<\\/span>");
for (auto &found : founds) {
std::replace(found.begin(), found.end(), ',', '.');
}
return founds;
}
void dumpVectorsToStderr(std::vector<std::wstring> &products, std::vector<std::wstring> &amounts, std::vector<std::wstring> &net_weights, std::vector<std::wstring> &prices) {
std::cerr << "Products: ";
for (auto &product : products) {
std::cerr << to_utf8(product) << "|[]|";
}
std::cerr << std::endl;
std::cerr << "Amounts: ";
for (auto &amount : amounts) {
std::wcerr << amount << " ";
}
std::cerr << std::endl;
std::cerr << "Net weights: ";
for (auto &net_weight : net_weights) {
std::wcerr << net_weight << " ";
}
std::cerr << std::endl;
std::cerr << "Prices: ";
for (auto &price : prices) {
std::wcerr << price << " ";
}
std::cerr << std::endl;
} }
Check parseOfdRuAnswer(std::string html) { Check parseOfdRuAnswer(std::string html) {
@ -119,6 +246,7 @@ Check parseOfdRuAnswer(std::string html) {
std::vector<std::wstring> products = find_products_in_html(trimmed); std::vector<std::wstring> products = find_products_in_html(trimmed);
std::vector<std::wstring> amounts = find_amounts_in_html(trimmed); std::vector<std::wstring> amounts = find_amounts_in_html(trimmed);
std::vector<std::wstring> net_weights = find_net_weights_in_names(products);
std::vector<std::wstring> prices = find_prices_in_html(trimmed); std::vector<std::wstring> prices = find_prices_in_html(trimmed);
if ((products.size() + amounts.size() + prices.size()) == 0) { if ((products.size() + amounts.size() + prices.size()) == 0) {
@ -133,6 +261,10 @@ Check parseOfdRuAnswer(std::string html) {
} }
if ((products.size() + amounts.size() + prices.size())/products.size() != 3) { if ((products.size() + amounts.size() + prices.size())/products.size() != 3) {
dumpVectorsToStderr(products, amounts, net_weights, prices);
//TOOD: make new setting "app_home" and get all path using it.
std::ofstream error_log(get_path_relative_to_home(".local/share/checks_parser/error_log.txt"), std::ios_base::app);
error_log << trimmed << std::endl;
std::cerr << "An error has occured during the parsing of html. Please, contact the developer." << std::endl; std::cerr << "An error has occured during the parsing of html. Please, contact the developer." << std::endl;
std::exit(-1); std::exit(-1);
} }
@ -140,9 +272,40 @@ Check parseOfdRuAnswer(std::string html) {
Check c; Check c;
for (int i = 0; i < products.size(); i ++) { for (int i = 0; i < products.size(); i ++) {
Goods goods(to_utf8(products[i]), std::stod(prices[i]), std::stod(amounts[i])); std::cout << "Adding to check: ";
std::cout << to_utf8(products[i]) << " " << to_utf8(prices[i]) << " " << to_utf8(net_weights[i]) << " " << to_utf8(amounts[i]) << std::endl;
Goods goods(to_utf8(products[i]), std::stod(prices[i]), to_utf8(net_weights[i]), std::stod(amounts[i]));
c.add_goods(goods); c.add_goods(goods);
} }
return c; return c;
} }
#endif // ifdef BUILD_OFD_MODE
#ifdef BUILD_OFD_BINARYEYE_SCAN
void generate_qr_code(std::string data) {
QRcode *qrCode = QRcode_encodeString(data.c_str(), 2, QR_ECLEVEL_L, QR_MODE_8, 1);
if (qrCode == NULL) {
std::cerr << "Error on generating qr code" << std::endl;
}
cv::Mat qrCodeImage = cv::Mat::zeros(qrCode->width, qrCode->width, CV_8UC3);
for (int y = 0; y < qrCode->width; y++) {
for (int x = 0; x < qrCode->width; x++) {
cv::rectangle(
qrCodeImage,
cv::Point(x, y),
cv::Point(x + 1, y + 1),
((qrCode->data[y * qrCode->width + x] & 1) ?
cv::Scalar(255., 255., 255.) : cv::Scalar(0., 0., 0.)
),
-1
);
}
}
cv::imwrite(get_path_relative_to_home(".local/share/checks_parser/binaryeye_connection.png"), qrCodeImage);
QRcode_free(qrCode);
}
#endif // ifdef BUILD_OFD_BINARYEYE_SCAN

View File

@ -12,11 +12,24 @@ std::string get_path_relative_to_home(std::string path);
template <typename T> template <typename T>
bool vector_contains_element(const std::vector<T> &vector, const T &to_find); bool vector_contains_element(const std::vector<T> &vector, const T &to_find);
template <class T>
bool areAllSizesEqual(const std::vector<T>& v1, const std::vector<T>& v2,
const std::vector<T>& v3, const std::vector<T>& v4);
std::vector<std::string> split(std::string, std::string); std::vector<std::string> split(std::string, std::string);
std::vector<std::wstring> split(std::wstring s, std::wstring delimiter);
#ifdef BUILD_OFD_MODE
Check parseOfdRuAnswer(std::string); Check parseOfdRuAnswer(std::string);
std::wstring trim_html_response(std::wstring& check); std::wstring trim_html_response(std::wstring& check);
#endif
#ifdef BUILD_OFD_BINARYEYE_SCAN
void generate_qr_code(std::string data);
std::string get_local_ip_address();
#endif
void fetch_and_download_modules();
#endif // UTILS_H #endif // UTILS_H