35 Commits

Author SHA1 Message Date
487707ba3e deployment 2025-03-17 00:06:19 +03:00
3dbc85f929 generate and show qr code 2025-03-15 15:12:53 +03:00
2b2127e3b5 restructure, change onDataDecode signal and succesfully parsing http request 2025-03-15 00:48:46 +03:00
f507ec8d67 starting http server with error handling 2025-03-14 18:24:42 +03:00
453f907bfa Merge pull request 'UI rework' (#3) from ui_rework into master 2025-03-14 01:27:59 +03:00
39c4bfb2fd fixed translations 2025-03-14 01:12:55 +03:00
33b54fb475 added ofd scene, working http server 2025-03-14 00:44:14 +03:00
b305fba2fd russian grammar 2025-03-12 12:53:43 +03:00
1ae724f925 added functionality to email text and ocr scenes 2025-03-11 23:31:08 +03:00
4c7a25c53e added ui for ofd 2025-03-11 19:37:58 +03:00
cb3d6c2a3f rework ui, add text from email scene 2025-03-09 21:23:36 +03:00
4f75e88b69 staging 2025-03-09 17:11:34 +03:00
29b9b58759 rework of mainwindow in progress 2025-03-09 16:05:37 +03:00
df522f07f7 merge 2025-03-08 17:35:05 +03:00
d41accd111 cleanup 2025-03-08 17:33:24 +03:00
957ccc9946 dirty minimal working version 2025-03-08 12:42:43 +03:00
7d42cbd111 unneeded dependencies 2025-03-07 16:36:12 +03:00
05563a5f82 removed unneeded dependency from readme 2025-03-03 23:26:14 +03:00
5ca16a4f76 translations 2025-03-03 22:52:09 +03:00
e60aafd653 separated translations as a new make target 2024-12-12 00:58:36 +03:00
a10271e595 added debian package 2024-12-09 19:30:48 +03:00
3a2901b49c added PKGBUILD 2024-12-09 19:06:49 +03:00
22922aecaa added handler on internal server error 2024-12-09 17:34:36 +03:00
baa8ae6e65 added russian readme 2024-12-09 17:06:35 +03:00
2ebcf68838 fix UI and translations 2024-12-09 16:27:30 +03:00
b135f8a94d readme changes 2024-12-07 02:18:03 +03:00
7290769750 readme update 2024-12-05 16:04:55 +03:00
64da9e9327 fixed language settings 2024-12-05 14:53:20 +03:00
b7b7c054d3 fixed loading system locale from wrong place 2024-12-05 13:58:23 +03:00
c478dcf8d4 embeding translations into qrc 2024-12-05 03:48:20 +03:00
7959bc5492 added language combo box in preferences 2024-12-04 18:44:40 +03:00
031c1d5792 translations 2024-12-04 04:35:51 +03:00
cca20abbfd pretty-printing settings.json 2024-12-04 04:05:02 +03:00
988dc0e133 upload icons 2024-12-04 01:08:08 +03:00
888f658a9c added icon 2024-12-04 01:07:48 +03:00
62 changed files with 4153 additions and 1175 deletions

3
.gitignore vendored
View File

@@ -35,6 +35,8 @@ Thumbs.db
/.qmake.cache /.qmake.cache
/.qmake.stash /.qmake.stash
*.qrc.depends
# qtcreator generated files # qtcreator generated files
*.pro.user* *.pro.user*
CMakeLists.txt.user* CMakeLists.txt.user*
@@ -121,3 +123,4 @@ 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

View File

@@ -2,96 +2,117 @@ cmake_minimum_required(VERSION 3.10)
project(checks-parser VERSION 0.1 LANGUAGES CXX) project(checks-parser VERSION 0.1 LANGUAGES CXX)
option(BUILD_TRANSLATIONS "Build translations?" ON)
include(FetchContent)
SET(CMAKE_BUILD_TYPE Debug)
set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON) 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(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets LinguistTools) find_package(Qt5Core REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets) find_package(Qt5 REQUIRED COMPONENTS LinguistTools)
find_package(Qt5 COMPONENTS LinguistTools) find_package(Qt5Gui REQUIRED)
find_package(Qt5Widgets REQUIRED)
find_package(Qt5UiTools REQUIRED)
set(PROJECT_SOURCES set(PROJECT_SOURCES
main.cpp main.cpp
mainwindow.cpp mainwindow.h mainwindow.cpp scenes/mainwindow.ui
mainwindow.h
mainwindow.ui
# Add other source files here that contain translatable strings goods/goods.h goods/goods.cpp
check/check.h check/check.cpp
parser/parser.h parser/parser.cpp
parser/module.h parser/module.cpp
output/output_options.h output/output_options.cpp
utils/utils.h utils/utils.cpp
image/checkimage.h image/checkimage.cpp
net/net.h net/net.cpp
settings/settings.h settings/settings.cpp
exceptions/ofdrequestexception.h exceptions/ofdrequestexception.cpp
emailtextscene.h emailtextscene.cpp scenes/emailtextscene.ui
ocrscene.h ocrscene.cpp scenes/ocrscene.ui
ofdscene.h ofdscene.cpp scenes/ofdscene.ui
outputdialog.h outputdialog.cpp scenes/outputdialog.ui
adjustpicturedialog.h adjustpicturedialog.cpp scenes/adjustpicturedialog.ui
image_redactor/imageredactor.h image_redactor/imageredactor.cpp
solvecaptchadialog.h solvecaptchadialog.cpp scenes/solvecaptchadialog.ui
) )
# Specify the UI files and source files for translation
set(TRANSLATION_SOURCES set(TRANSLATION_SOURCES
main.cpp main.cpp
mainwindow.cpp mainwindow.h mainwindow.ui mainwindow.cpp mainwindow.h scenes/mainwindow.ui
outputdialog.cpp outputdialog.h outputdialog.ui emailtextscene.cpp emailtextscene.h scenes/emailtextscene.ui
settingsdialog.cpp settingsdialog.h settingsdialog.ui ocrscene.cpp ocrscene.h scenes/ocrscene.ui
solvecaptchadialog.cpp solvecaptchadialog.h solvecaptchadialog.ui ofdscene.cpp ofdscene.h scenes/ofdscene.ui
adjustpicturedialog.cpp adjustpicturedialog.h adjustpicturedialog.ui outputdialog.h outputdialog.cpp scenes/outputdialog.ui
adjustpicturedialog.h adjustpicturedialog.cpp scenes/adjustpicturedialog.ui
# Add other .cpp or .ui files that need translation here solvecaptchadialog.h solvecaptchadialog.cpp scenes/solvecaptchadialog.ui
) )
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) set(TS_FILES
qt_add_executable(checks-parser translations/en_US.ts
MANUAL_FINALIZATION translations/ru_RU.ts
)
if (BUILD_TRANSLATIONS)
qt5_create_translation(QM_FILES "${TRANSLATION_SOURCES}" ${TS_FILES})
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)
add_custom_target(translations ALL DEPENDS ${QM_FILES})
add_custom_target(resources ALL DEPENDS ${TRANSLATIONQRC})
add_dependencies(resources translations)
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 "")
list(APPEND SOURCES ${MEDIAQRC})
list(APPEND SOURCES ${SCENESQRC})
if (BUILD_TRANSLATIONS)
list(APPEND SOURCES ${TRANSLATIONQRC})
endif()
if(ANDROID)
add_library(checks-parser SHARED
${PROJECT_SOURCES} ${PROJECT_SOURCES}
${SOURCES}
) )
# Generate translation files for Qt 6
qt_add_translation(TRANSLATIONS "${TRANSLATION_SOURCES}")
else() else()
if(ANDROID) add_executable(checks-parser
add_library(checks-parser SHARED ${PROJECT_SOURCES}
${PROJECT_SOURCES} ${SOURCES}
) )
else()
# Generate translation files for Qt 5
# QT5_ADD_TRANSLATION()
qt5_create_translation(QM_FILES "${TRANSLATION_SOURCES}" translations/en_US.ts translations/ru_RU.ts)
add_executable(checks-parser
${PROJECT_SOURCES}
goods/goods.h goods/goods.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
utils/utils.h utils/utils.cpp
image/checkimage.h image/checkimage.cpp
net/net.h net/net.cpp
settings/settings.h settings/settings.cpp
settingsdialog.h settingsdialog.cpp settingsdialog.ui
adjustpicturedialog.h adjustpicturedialog.cpp adjustpicturedialog.ui
image_redactor/imageredactor.h image_redactor/imageredactor.cpp
solvecaptchadialog.h solvecaptchadialog.cpp solvecaptchadialog.ui
exceptions/ofdrequestexception.h exceptions/ofdrequestexception.cpp
${QM_FILES}
)
# configure_file(translations.qrc ${CMAKE_BINARY_DIR} COPYONLY)
# QT5_ADD_TRANSLATION(TRANSLATIONS ${CMAKE_SOURCE_DIR} translations/en_US.ts)
endif()
endif() endif()
target_link_libraries(checks-parser PRIVATE Qt${QT_VERSION_MAJOR}::Widgets) target_link_libraries(checks-parser PRIVATE Qt5::Widgets Qt5::UiTools)
target_include_directories(checks-parser PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/image_redactor)
set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER org.foxarmy.checks-parser)
# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
# If you are developing for iOS or macOS you should consider setting an
# explicit, fixed bundle identifier manually though.
if(${QT_VERSION} VERSION_LESS 6.1.0)
set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.example.checks-parser)
endif()
set_target_properties(checks-parser PROPERTIES set_target_properties(checks-parser PROPERTIES
${BUNDLE_ID_OPTION} ${BUNDLE_ID_OPTION}
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
@@ -107,17 +128,34 @@ install(TARGETS checks-parser
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
) )
if(QT_VERSION_MAJOR EQUAL 6) if(WIN32)
qt_finalize_executable(checks-parser) #????
set(OpenCV_DIR /usr/local/lib/cmake/opencv4)
endif() endif()
find_package(OpenCV REQUIRED) FetchContent_Declare(httplib SYSTEM
GIT_REPOSITORY https://github.com/yhirose/cpp-httplib
GIT_TAG c765584e6b1055fe0dfe3e9e6d1b4b09aa305070
GIT_SHALLOW TRUE)
FetchContent_MakeAvailable(httplib)
find_package(OpenCV REQUIRED COMPONENTS core imgproc imgcodecs)
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})
include_directories( ${OpenCV_INCLUDE_DIRS} ) include_directories( ${OpenCV_INCLUDE_DIRS} )
target_include_directories(checks-parser PUBLIC ${OpenCV_INCLUDE_DIRS})
target_link_libraries(checks-parser PRIVATE -lzbar) target_link_libraries(checks-parser PRIVATE -lzbar)
target_link_libraries(checks-parser PRIVATE -ltesseract) 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} ) target_link_libraries(checks-parser PRIVATE ${OpenCV_LIBS})
target_link_libraries(checks-parser PRIVATE httplib)
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8) if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8)
target_link_libraries(checks-parser PRIVATE -lstdc++fs) target_link_libraries(checks-parser PRIVATE -lstdc++fs)
endif() endif()

View File

@@ -1,122 +0,0 @@
cmake_minimum_required(VERSION 3.16)
project(checks-parser VERSION 0.1 LANGUAGES CXX)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOUIC_SEARCH_PATHS Designer)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
set(PROJECT_SOURCES
main.cpp
mainwindow.cpp
mainwindow.h
mainwindow.ui
)
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
qt_add_executable(checks-parser
MANUAL_FINALIZATION
${PROJECT_SOURCES}
)
SET (LANGUAGES rus eng)
SET (TRANSLATIONS_PATH "./translations")
foreach (LANGUAGE ${LANGUAGES})
set (TS ${TRANSLATIONS_PATH}/${LANGUAGE}.ts)
set (QM ${TRANSLATIONS_PATH}/${LANGUAGE}.qm)
set (TRANSLATIONS ${TRANSLATIONS} ${TS})
set (TRANSLATIONS_BINARY ${TRANSLATIONS_BINARY} ${QM})
add_custom_command(
OUTPUT ${QM}
COMMAND ${QT_LRELEASE_EXECUTABLE} ${TS}
MAIN_DEPENDENCY ${TS}
)
endforeach()
qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} translations/english.ts)
# Define target properties for Android with Qt 6 as:
# set_property(TARGET checks-parser APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
# ${CMAKE_CURRENT_SOURCE_DIR}/android)
# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation
else()
if(ANDROID)
add_library(checks-parser SHARED
${PROJECT_SOURCES}
)
# Define properties for Android with Qt 5 after find_package() calls as:
# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
else()
add_executable(checks-parser
${PROJECT_SOURCES}
goods/goods.h goods/goods.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
utils/utils.h utils/utils.cpp
image/checkimage.h image/checkimage.cpp
net/net.h net/net.cpp
settings/settings.h settings/settings.cpp
settingsdialog.h settingsdialog.cpp settingsdialog.ui
adjustpicturedialog.h adjustpicturedialog.cpp adjustpicturedialog.ui
imageview/imageview.h imageview/imageview.cpp
image_redactor/imageredactor.h image_redactor/imageredactor.cpp
solvecaptchadialog.h solvecaptchadialog.cpp solvecaptchadialog.ui
exceptions/ofdrequestexception.h exceptions/ofdrequestexception.cpp
${TRANSLATIONS}
${QM_FILES}
${QM}
${TS}
)
endif()
endif()
add_custom_target(translations DEPENDS ${QM_FILES})
add_dependencies(checks-parser translations)
target_link_libraries(checks-parser PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
# If you are developing for iOS or macOS you should consider setting an
# explicit, fixed bundle identifier manually though.
if(${QT_VERSION} VERSION_LESS 6.1.0)
set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.example.checks-parser)
endif()
set_target_properties(checks-parser PROPERTIES
${BUNDLE_ID_OPTION}
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
MACOSX_BUNDLE TRUE
WIN32_EXECUTABLE TRUE
)
include(GNUInstallDirs)
install(TARGETS checks-parser
BUNDLE DESTINATION .
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
if(QT_VERSION_MAJOR EQUAL 6)
qt_finalize_executable(checks-parser)
endif()
find_package(OpenCV REQUIRED)
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 ${OpenCV_LIBS} )

View File

@@ -1,16 +1,19 @@
-->[Русская версия](https://git.foxarmy.org/leca/checks-parser/src/branch/master/README.ru.md)<--
# Checks parser # Checks parser
checks parser is a program that help parsing different checks to csv. checks parser is a program that help parsing different checks to csv.
!!!CURRENTLY SUPPORTED ONLY RUSSIAN CHECKS!!! !!!CURRENTLY SUPPORTED ONLY RUSSIAN CHECKS!!!
To know why, see [this section](#Checks-from-different-countries) To know why, see [this section](https://git.foxarmy.org/leca/checks-parser#checks-from-different-countries)
# Usage # Usage
For more detailed description, please, refer to [the wiki](https://git.foxarmy.org/leca/checks-parser/wiki/Description-%5BEN%5D)
### Input ### Input
Ways you can input a check to this programm: Ways you can input a check to this programm:
* Via image (it uses OCR(Optical Character Recognition) to parse check content. The picture of a check must be contrast and well-lined (text must be perpendicular to right and left borders of an image) enough in order to be parsed well.) * Via image (it uses OCR(Optical Character Recognition) to parse check content. The picture of a check must be contrast and well-lined (text must be perpendicular to right and left borders of an image) enough in order to be parsed well.) OCR is not a magic wand :(
* Via plaintext, copied from an E-Mail. Just copy&paste text from your email, pick a correct store type (autodetect is in my plans!) and parse. * Via plaintext, copied from an E-Mail. Just copy&paste text from your email, pick a correct store type (autodetect is in my plans!) and parse.
* Via a picture of a check. Be sure to make the image straight and sharp. OCR is not a magic wand :( * Via QRCode on check (this method queries check content from OFD (ОФД, Оператор Фискальных Данных in Russian) (My program makes requests to ofd.ru)).
* Via QrCode on check (OFD (ОФД, Оператор Фискальных Данных in Russian)).
### Output ### Output
At the start of writing this program, I considered 3 or more output formats: csv, xlsx and ods. But throught the development I understood that most of modern table processor (i.e. electronic tables) can import csv much better than I'd be writing a shitty export module, adding more dependencies and shitty code to the codebase. So I decided that there's no need to use anything other than csv format. At the start of writing this program, I considered 3 or more output formats: csv, xlsx and ods. But throught the development I understood that most of modern table processor (i.e. electronic tables) can import csv much better than I'd be writing a shitty export module, adding more dependencies and shitty code to the codebase. So I decided that there's no need to use anything other than csv format.
@@ -26,15 +29,17 @@ In general, you need to install following dependencies in order to build that ap
* curl * curl
* nlohmann-json * nlohmann-json
* qt5 * qt5
* vtk * 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
##### Arch Linux-based ##### Arch Linux-based
I recommend using aur helper (I use yay) to install dependencies. Or, if you're masochist, you can build all by yourself /shrug 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 sudo cmake git coreutils base-devel eigen qt5-base mbedtls gtkglext opencv opencv2 zbar nlohmann-json tesseract tesseract-data-rus vtk yay -S base-devel qt5-base opencv zbar nlohmann-json tesseract qrencode
#Install a language package for OCR. Replace ``LANG` to your language. For example, ``tesseract-data-rus`` for russian language
yay -S tesseract-data-LANG
#Clone and compile an app #Clone and compile an app
git clone https://git.foxarmy.org/leca/checks-parser git clone https://git.foxarmy.org/leca/checks-parser
cd checks-parser cd checks-parser
@@ -48,9 +53,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```
###### 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```
Next steps are identical for every debian-based distro Next steps are identical for every debian-based distro
``` ```
@@ -64,12 +69,20 @@ sudo make install
``` ```
### Windows ### Windows
Maybe See [Precompiled binaries](https://git.foxarmy.org/leca/checks-parser#precompiled-binaries)
### Mac OS ### Mac OS
Probably not, I do not have nor desire or time. But if you can maintain that program on Mac, I'd be grateful! Please, contact me, if you can! Probably not, I do not have nor desire or time. But if you can maintain that program on Mac, I'd be grateful! Please, contact me, if you can!
## Precompiled binaries ## Precompiled binaries
I plan to make precompiled binaries for Linux and Windows. Maybe I will put it on AUR. I also think that I will be making an AppImage Currently I have published the program to the [AUR](https://aur.archlinux.org/packages/checks-parser-git).
Every new release will certainly contain AppImage and tarball. I am working towards binaries for Windows and deb packets. Expect them to appear in next releases!
# Special thanks
HyperFlint (@hyperflint:foxarmy.org) - for the great idea to use OFD and a huge help in release preparations!
https://check.ofd.ru - for providing a way to request data from FNS.
# Contribution # Contribution
@@ -79,11 +92,12 @@ If you want to contribute to the project, you can do it by some of the following
I live in Russia and only know how Russian state checks system works. If you live in another country and want to help me with adding support to checks from your country - feel free to contact me! I live in Russia and only know how Russian state checks system works. If you live in another country and want to help me with adding support to checks from your country - feel free to contact me!
## Issues and PRs ## Issues and PRs
If you have found a bug, or want to suggest a feature - don't hesitate to open an issue / PR! If you have found a bug, or want to suggest a feature - don't hesitate to open an issue / a PR!
## Tell friends ## Tell friends
You can help me by distributing that program. If you know people that are in search of such program, please let them know about its existance! You can help me by distributing that program. If you know people that are in search of such program, please let them know about its existance!
## Donate ## Donate
```XMR 45ZjyH5YWdRfKxLoKEBYaiHUTcP5Z8Gv64QQxmabbooPAa7KPBxZLmqft5ohKXn5VpHiVj1x9JKCcAcAjdu9jA8b5N8XqR7``` ```XMR 45ZjyH5YWdRfKxLoKEBYaiHUTcP5Z8Gv64QQxmabbooPAa7KPBxZLmqft5ohKXn5VpHiVj1x9JKCcAcAjdu9jA8b5N8XqR7```

103
README.ru.md Normal file
View File

@@ -0,0 +1,103 @@
-->[English version](https://git.foxarmy.org/leca/checks-parser/src/branch/master/README.md)<--
# Чек парсер
Чек парсер - это приложение, позволяющее доставать содержимое чека и переводить его в .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/wiki/Description-%5BRU%5D)
### Ввод данных
Доступны следующие способы ввода данных:
* Через изображениие (используется OCR(Optical Character Recognition, Оптическое распознавание символов), чтобы прочитать содержимое чека. Изображение чека должно быть контрастным и выровненным (текст обязан быть перпендикулярным к границам изображения) хорошо, чтобы нормально прочитаться. OCR - не волшебная палочка :(
* Через простой текст, скопированный из эл. письма. Скопируйте и вставьте текст с вашего письма, выберите подходящий магазин (автодетект в планах!) и парсите.
* Через QRCode на чеке (этот метод запрашивает данные у ОФД (Оператор Фискальных Данных), в данном конкретном случае, к ofd.ru).
### Вывод данных
На начальном этапе разработки программы, Я задумывался о 3-х или более форматов вывода: csv, xlsx и ods. Но, по мере разработки, я понял, что большинство современных табличных процессоров (электронных таблиц) способны импортировать в себя csv гораздо лучше, чем смог бы написать я сам. Так что я решил не делать вывод во все остальные форматы, кроме csv.
Чтобы экспортировать вам нужно: указать путь до файла, если вы желаете, вы можете изменить порядок и/или переименовать (алиасы) столбцы, выбрать печатать или не печатать заголовок (алиасы столбцов) и "итого".
# Установка
## Сборка из исходников
В целом, вам нужно установить следующие зависимости, чтобы собрать приложение (я предполагаю, что вы уже имеете на системе базовые пакеты вроде cmake, make, gcc, git и так далее):
* tesseract (также вам нужно будет установить языковой пакет для него, например tesseract-data-rus на Arch Linux или tesseract-ocr-rus на Debian Linux.)
* opencv
* zbar
* curl
* nlohmann-json
* qt5
Пожалуйста, не стесняйтесь и открывайте issue, если вы не можете собрать приложение. Я помогу вам, и если вы собираете приложение на дистрибутиве, который здесь не перечислен, как только мы решим вашу проблему, я добавлю новый дистрибутив в этот список!
### Linux
##### Arch Linux и ответвления
Я рекомендую использовать помощник для АУРа (я использую yay) чтобы установить зависимости. Или, если вы мазохист, можете собрать все зависимости ручками ¯\\\_()\_
```
#Установка зависимостей
yay -S base-devel qt5-base opencv zbar nlohmann-json tesseract qrencode
#Установка языкового пакета для OCR. Замените ``LANG` на желаемый язык. Например, ``tesseract-data-rus`` для русского языка
yay -S tesseract-data-LANG
#Загрузка исходгого кода и сборка приложения
git clone https://git.foxarmy.org/leca/checks-parser
cd checks-parser
cmake .
make -j{nproc}
#Если вы хотите скопировать запускной файл в свою систему, исполните:
sudo make install
```
##### Debian и ответвления
В debian и ответвлениях большинство, но не все, имена пакетов одинаковы.
Установка зависимостей для различных debian дистрибутивов:
###### 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```
###### 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```
Следующие шаги идеинтичны для всех дистрибутивов, основанных на debian:
```
#Загрузка исходного кода и сборка приложения
git clone https://git.foxarmy.org/leca/checks-parser
cd checks-parser
cmake .
make -j{nproc}
#Если вы хотите скопировать запускной файл в свою систему, исполните:
sudo make install
```
### Windows
Смотрите [бинарники](https://git.foxarmy.org/leca/checks-parser/src/branch/master/README.ru.md#бинарники)
### Mac OS
Скорее всего нет, у меня нет ни времени, ни желания, ни устройства. Но если вы можете собирать программу на Mac OS, я буду рад, если вы поможете. Пожалуйста, свяжитесь со мной, если можете!
## Бинарники
На текущий момент я опубликовал программу в [АУР](https://aur.archlinux.org/packages/checks-parser-git).
Каждый релиз будет содержать AppImage и арчёвский tarball. Я работаю над бинарниками для Windows и .deb пакетами. Ожидайте их в следующих релизах!
# Особое спасибо
HyperFlint (@hyperflint:foxarmy.org) - за гениальную идею использовать ОФД и огромную помощь в подготовке проекта к релизу!
https://check.ofd.ru - за способ вытаскивать данные о чеках из ФНС.
# Помощь
Если вы хотите помочь проекту, вы можете сделать это следующими способами:
## Чеки из других стран
Я живу в России и знаком только с местной системой чеков. Если вы живёте в другой стране и хотите помочь мне с поддержкой чеков из Вашей страны - свяжитесь со мной!
## Issues и PRs
Если вы нашли баг или хотите предложить что-то в программу - не стесняйтесь и открывайте issue или PR!
## Рассказать друзьями
Вы можете помочь проекту, распространяя программу. Если вы знаете людей, которые ищут подобную программу, пожалуйста, дайте им знать о существовании таковой!
## Пожертвования
```XMR 45ZjyH5YWdRfKxLoKEBYaiHUTcP5Z8Gv64QQxmabbooPAa7KPBxZLmqft5ohKXn5VpHiVj1x9JKCcAcAjdu9jA8b5N8XqR7```

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

@@ -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

@@ -4,10 +4,7 @@ FROM archlinux
RUN pacman --noconfirm -Sy RUN pacman --noconfirm -Sy
#Build dependencies #Build dependencies
RUN pacman --noconfirm -S sudo cmake git coreutils base-devel eigen RUN pacman --noconfirm -S sudo cmake git coreutils base-devel qt5-base
#Dependencies from repos
RUN pacman --noconfirm -S qt5-base mbedtls
RUN echo "MAKEFLAGS=\"-j${nproc}\"" >> /etc/makepkg.conf RUN echo "MAKEFLAGS=\"-j${nproc}\"" >> /etc/makepkg.conf
@@ -24,15 +21,13 @@ RUN git clone https://aur.archlinux.org/yay.git && \
makepkg -si --noconfirm && \ makepkg -si --noconfirm && \
cd .. && sudo rm -rf yay cd .. && sudo rm -rf yay
RUN yay -Sy --noconfirm gtkglext RUN yay -S opencv zbar nlohmann-json tesseract tesseract-data-rus
RUN yay -S --noconfirm cpr opencv opencv2 nlohmann-json tesseract tesseract-data-rus
#building #building
WORKDIR /home/checks-parser WORKDIR /home/checks-parser
RUN git clone https://git.foxarmy.org/leca/checks-parser && \ RUN git clone https://git.foxarmy.org/leca/checks-parser && \
cd checks-parser && \ cd checks-parser && \
mkdir build && cd build && \ cmake . && \
cmake .. && \
make -j ${nproc} && \ make -j ${nproc} && \
sudo make install sudo make install

Binary file not shown.

Before

Width:  |  Height:  |  Size: 627 KiB

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 627 KiB

View File

@@ -1,7 +0,0 @@
# Generated by linuxdeployqt
# https://github.com/probonopd/linuxdeployqt/
[Paths]
Prefix = ./
Plugins = plugins
Imports = qml
Qml2Imports = qml

View File

@@ -1,7 +0,0 @@
# Generated by linuxdeployqt
# https://github.com/probonopd/linuxdeployqt/
[Paths]
Prefix = ../
Plugins = plugins
Imports = qml
Qml2Imports = qml

4
deploy/appimage/AppRun Normal file
View File

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

View File

@@ -0,0 +1,71 @@
FROM ubuntu:20.04
# Installing dependencies
RUN apt update
RUN DEBIAN_FRONTEND=noninteractive 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
RUN DEBIAN_FRONTEND=noninteractive apt install -y wget git cmake make gcc g++ fuse
# For gcc 12
RUN DEBIAN_FRONTEND=noninteractive apt install -y libmpc-dev libmpfr-dev libgmp-dev
# The program uses std::regex_constants::multiline and some other C++17 things that are not found in gcc for Ubuntu Focal. Thus, we should compile it.
WORKDIR /
RUN wget https://mirror.linux-ia64.org/gnu/gcc/releases/gcc-12.3.0/gcc-12.3.0.tar.gz
RUN tar xf gcc-12.3.0.tar.gz
WORKDIR /gcc-12.3.0
RUN ./configure --disable-multilib
RUN make -j $(nproc) && make install
WORKDIR /
RUN rm -rf gcc-12.3.0
ENTRYPOINT bash
# 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 /appimage
RUN mkdir -p AppDir
COPY deploy/appimage/checks-parser.desktop AppDir
COPY icon.png AppDir/checks-parser.png
COPY deploy/appimage/AppRun AppDir
RUN chmod +x AppDir/AppRun
#Copy only necessities
COPY assets ./assets
COPY check ./check
COPY exceptions ./exceptions
COPY goods ./goods
COPY image ./image
COPY image_redactor ./image_redactor
COPY output ./output
COPY parser ./parser
COPY settings ./settings
COPY scenes ./scenes
COPY net ./net
COPY translations ./translations
COPY utils ./utils
COPY ./*cpp ./*.h ./*.ui ./*.qrc CMakeLists.txt .
RUN mkdir build
WORKDIR /appimage/build
RUN cmake -DBUILD_TRANSLATIONS=on .. && make -j 8
WORKDIR /appimage/AppDir/usr/bin
RUN cp /appimage/build/checks-parser .
WORKDIR /appimage
RUN LD_LIBRARY_PATH=LD_LIBRARY_PATH=/usr/local/lib64 linuxdeployqt AppDir/usr/bin/checks-parser -no-copy-copyright-files -appimage
ENTRYPOINT bash

View File

@@ -4,4 +4,3 @@ Exec=usr/bin/checks-parser
Icon=checks-parser Icon=checks-parser
Type=Application Type=Application
Categories=Utility; Categories=Utility;
X-AppImage-Version=41463c7

View File

@@ -1,4 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
rm -rf AppDir
mkdir -p AppDir
mkdir -p AppDir/usr/bin mkdir -p AppDir/usr/bin
mkdir -p AppDir/usr/lib mkdir -p AppDir/usr/lib
mkdir -p AppDir/usr/share/tesseract-ocr/4.00/tessdata mkdir -p AppDir/usr/share/tesseract-ocr/4.00/tessdata
@@ -21,6 +24,8 @@ export TESSDATA_PREFIX=\$APPDIR/usr/share/tesseract-ocr/4.00/tessdata
\$APPDIR/usr/bin/checks-parser" \ \$APPDIR/usr/bin/checks-parser" \
> AppDir/AppRun > AppDir/AppRun
cp ../../icon.png AppDir/checks-parser.png
chmod +x AppDir/AppRun chmod +x AppDir/AppRun
cp ../../checks-parser AppDir/usr/bin cp ../../checks-parser AppDir/usr/bin
linuxdeployqt AppDir/usr/bin/checks-parser -no-copy-copyright-files -appimage linuxdeployqt AppDir/usr/bin/checks-parser -no-copy-copyright-files -appimage

36
deploy/archlinux/PKGBUILD Normal file
View File

@@ -0,0 +1,36 @@
# Maintainer: Leca <leca@foxarmy.org>
pkgname=checks-parser-git
pkgver=alpha_0.0.2
pkgrel=1
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')
makedepends=('cmake' 'make' 'gcc' 'git' 'qt5-tools')
checkdepends=()
optdepends=('tesseract-data-rus: scan russian checks with OCR')
provides=()
conflicts=()
replaces=()
backup=()
options=()
install=
changelog=
source=("checks-parser-git::git+$url")
noextract=()
sha256sums=('SKIP')
build() {
cd "$pkgname"
cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr .
make -j ${nproc}
}
package() {
cd "$pkgname"
install -Dm644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
make DESTDIR="$pkgdir/" PREFIX="/usr" install
}

30
deploy/debian/package.sh Executable file
View File

@@ -0,0 +1,30 @@
#!/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

45
emailtextscene.cpp Normal file
View File

@@ -0,0 +1,45 @@
#include "emailtextscene.h"
#include "ui_emailtextscene.h"
#include <QMessageBox>
#include <iostream>
#include <outputdialog.h>
#include <check/check.h>
EmailTextScene::EmailTextScene(QWidget *parent)
: QWidget(parent)
, ui(new Ui::EmailTextScene) {
ui->setupUi(this);
auto modules = parser.get_modules_names();
for (auto &module : modules) {
ui->store_combo_box->addItem(QString::fromStdString(module));
}
}
EmailTextScene::~EmailTextScene() {
delete ui;
}
void EmailTextScene::on_parse_button_clicked() {
std::wstring checkContent = ui->check_content->toPlainText().toStdWString();
parser.set_module(parser.search_modules()[ui->store_combo_box->currentIndex()]);
std::vector<Goods> goods = parser.parse(checkContent);
if (goods.size() == 0) {
QMessageBox infoDialog;
infoDialog.setText(tr("An error has occured. Check was matched incorrectly. Vector sizes are different. Please, contact the developer."));
infoDialog.setIcon(QMessageBox::Critical);
infoDialog.setWindowTitle(tr("Error in parsing"));
infoDialog.exec();
return;
}
Check check;
check.add_goods(goods);
OutputDialog d(this, check);
d.show();
d.exec();
}

27
emailtextscene.h Normal file
View File

@@ -0,0 +1,27 @@
#ifndef EMAILTEXTSCENE_H
#define EMAILTEXTSCENE_H
#include "parser/parser.h"
#include <QWidget>
namespace Ui {
class EmailTextScene;
}
class EmailTextScene : public QWidget
{
Q_OBJECT
public:
explicit EmailTextScene(QWidget *parent = nullptr);
~EmailTextScene();
private slots:
void on_parse_button_clicked();
private:
Ui::EmailTextScene *ui;
Parser parser;
};
#endif // EMAILTEXTSCENE_H

BIN
icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

116
icon.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 649 KiB

View File

@@ -1,7 +1,6 @@
#include <opencv2/imgcodecs.hpp>
#include <string> #include <string>
#include <tesseract/baseapi.h> #include <tesseract/baseapi.h>
#include <leptonica/allheaders.h>
#include <opencv2/opencv.hpp>
#include "checkimage.h" #include "checkimage.h"
CheckImage::CheckImage(std::string path) { CheckImage::CheckImage(std::string path) {

168
main.cpp
View File

@@ -12,18 +12,159 @@
# include <filesystem> # include <filesystem>
using namespace std::filesystem; using namespace std::filesystem;
#endif #endif
#include <QDateTime>
#include <QFile>
#include <QStackedLayout>
#include <QTextStream>
#include <QTranslator> #include <QTranslator>
#include <emailtextscene.h>
#include <ocrscene.h>
#include <ofdscene.h>
#include <qpushbutton.h>
#include <parser/parser.h>
static QWidget *loadUI(QWidget *parent, std::string filename) {
QUiLoader loader;
QFile file(QString::fromStdString(filename));
file.open(QIODevice::ReadOnly);
return loader.load(&file, parent);
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
curl_global_init(CURL_GLOBAL_ALL); srand(time(0));
std::string program_data_path = get_path_relative_to_home(".local/share/checks_parser"); QApplication app(argc, argv);
create_directories(program_data_path);
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);
QTranslator translator;
QString lang = "en_US";
if (s.get_all_settings().contains("language")) {
lang = QString::fromStdString(s.get_all_settings()["language"]);
} else if (translator.load(":/translation/"+QLocale::system().name()+".qm")) {
lang = QLocale::system().name();
} else {
lang = QString::fromStdString("en_US");
}
std::cout << "Using locale: " << lang.toStdString() << std::endl;
translator.load(":/translation/" + lang + ".qm");
app.installTranslator(&translator);
QUiLoader loader;
QWidget *window = new QWidget();
QStackedLayout *sceneLayout = new QStackedLayout;
// Main Window setup
QWidget *mainwindowscene = loadUI(window, ":/scenes/scenes/mainwindow.ui");
// Main Window buttons setup
QPushButton *text_from_email_button = ((MainWindow *)mainwindowscene)->findChild<QPushButton *>("text_from_email_button");
QPushButton *ocr_button = ((MainWindow *)mainwindowscene)->findChild<QPushButton *>("ocr_button");
QPushButton *ofd_button = ((MainWindow *)mainwindowscene)->findChild<QPushButton *>("ofd_button");
QObject::connect(text_from_email_button, &QPushButton::clicked, [&]() {
// Text from email scene
sceneLayout->setCurrentIndex(1);
sceneLayout->widget(1)->show();
});
QObject::connect(ocr_button, &QPushButton::clicked, [&]() {
// OCR scene
sceneLayout->setCurrentIndex(2);
sceneLayout->widget(2)->show();
});
QObject::connect(ofd_button, &QPushButton::clicked, [&]() {
// OFD scene
sceneLayout->setCurrentIndex(3);
sceneLayout->widget(3)->show();
});
EmailTextScene *emailTextScene = new EmailTextScene();
OCRScene *ocrscene = new OCRScene();
OFDScene *ofdscene = new OFDScene();
sceneLayout->addWidget(mainwindowscene);
sceneLayout->addWidget(emailTextScene);
sceneLayout->addWidget(ocrscene);
sceneLayout->addWidget(ofdscene);
//Setting all back buttons
for (uint32_t sceneIndex = 0; sceneIndex < sceneLayout->count(); sceneIndex ++) {
auto scene = sceneLayout->widget(sceneIndex);
QPushButton *back_button = scene->findChild<QPushButton *>("back_button");
if (back_button == nullptr) continue;
QObject::connect(back_button, &QPushButton::clicked, [&]() {
sceneLayout->setCurrentIndex(0);
});
}
window->setLayout(sceneLayout);
window->show();
app.exec();
return 0;
// QApplication app(argc, argv);
// QWidget *window = new QWidget;
// QStackedLayout *stackedLayout = new QStackedLayout;
// QWidget *scene1 = new QWidget;
// QWidget *scene2 = new QWidget;
// // Add some widgets to each scene
// QPushButton *button1 = new QPushButton("Switch to Scene 2");
// scene1->setLayout(new QVBoxLayout);
// scene1->layout()->addWidget(button1);
// QPushButton *button2 = new QPushButton("Switch to Scene 1");
// scene2->setLayout(new QVBoxLayout);
// scene2->layout()->addWidget(button2);
// // Add the scenes to the stacked layout
// stackedLayout->addWidget(scene1);
// stackedLayout->addWidget(scene2);
// // Set the layout of the window
// window->setLayout(stackedLayout);
// // Connect the buttons to switch scenes
// QObject::connect(button1, &QPushButton::clicked, [&]() {
// stackedLayout->setCurrentIndex(1);
// });
// QObject::connect(button2, &QPushButton::clicked, [&]() {
// stackedLayout->setCurrentIndex(0);
// });
// window->show();
// app.exec();
// return 0;
curl_global_init(CURL_GLOBAL_ALL);
std::string program_data_path = get_path_relative_to_home(".local/share/checks_parser");
create_directories(program_data_path);
// std::string settings_file_path =
// get_path_relative_to_home(".local/share/checks_parser/settings.json");
// Settings s(settings_file_path);
Net n; Net n;
Parser p; Parser p;
@@ -42,11 +183,22 @@ int main(int argc, char *argv[]) {
QApplication a(argc, argv); QApplication a(argc, argv);
QTranslator translator; // QTranslator translator;
if(!translator.load(QLocale::system().name())) { // QString lang = "en_US";
translator.load("en_US");
} // if (s.get_all_settings().contains("language")) {
a.installTranslator(&translator); // lang = QString::fromStdString(s.get_all_settings()["language"]);
// } else if (translator.load(":/translation/"+QLocale::system().name()+".qm")) {
// lang = QLocale::system().name();
// } else {
// lang = QString::fromStdString("en_US");
// }
// std::cout << "Using locale: " << lang.toStdString() << std::endl;
// translator.load(":/translation/" + lang + ".qm");
// a.installTranslator(&translator);
MainWindow w; MainWindow w;
w.update(); w.update();
w.show(); w.show();

View File

@@ -1,208 +1,15 @@
#include "mainwindow.h" #include "mainwindow.h"
#include "./ui_mainwindow.h" #include "ui_mainwindow.h"
#include "check/check.h" #include <iostream>
#include "exceptions/ofdrequestexception.h"
#include "goods/goods.h"
#include "outputdialog.h"
#include "adjustpicturedialog.h"
#include "settingsdialog.h"
#include "solvecaptchadialog.h"
#include <QFileDialog>
#include <QMessageBox>
#include "image/checkimage.h"
#include "utils/utils.h"
#include <opencv2/objdetect.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <zbar.h>
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();
std::cout << "test" << std::endl;
} }
MainWindow::~MainWindow() { delete ui; } MainWindow::~MainWindow() {
delete ui;
void MainWindow::setupStoresList() {
parser = *(new Parser());
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) {
std::string checkContent = Net().fetch_check_data_from_ofdru(
ui->fn_edit->text().toStdString(),
ui->fd_edit->text().toStdString(),
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;
}
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(), "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();
}
return;
}
std::wstring check_plaintext = s.toStdWString();
parser.set_module(parser.search_modules()[0]);
std::vector<Goods> c = parser.parse(check_plaintext);
if (c.size() == 0) {
std::cerr << "An error has occured. Check was matched incorrectly. Vector sizes are different" << std::endl;
return;
}
for (auto& g : c) {
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());
connect(&dialog, &AdjustPictureDialog::decodedData, this, &MainWindow::onDecodedData);
dialog.exec();
ui->picture_ofd->setPixmap(QPixmap(filename));
ui->picture_ofd->setScaledContents(true);
}
void MainWindow::onDecodedData(std::string data) {
std::string delimiter = "&";
std::vector<std::string> dataSplit = split(data, delimiter);
std::cout << data << std::endl;
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");
ui->dateTimeEdit->setDateTime(datetime);
int type = std::stoi(split(dataSplit[5], "=")[1]);
ui->fundIncomeCombo->setCurrentIndex(type - 1);
std::string total = split(dataSplit[1], "=")[1];
ui->total_edit->setText(QString::fromStdString(total));
}
void MainWindow::on_chooseImageButton_ocr_clicked()
{
QString filename = QFileDialog::getOpenFileName();
if (filename == "") {
QMessageBox infoDialog;
infoDialog.setText(tr("Please, select a picture to scan"));
infoDialog.setIcon(QMessageBox::Critical);
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());
std::string parsed = i.parse_text();
ui->picture_ocr->setPixmap(QPixmap(filename));
ui->picture_ocr->setScaledContents(true);
ui->checkContentFromImage->setPlainText(QString::fromStdString(parsed));
}

219
mainwindow.cpp.old Normal file
View File

@@ -0,0 +1,219 @@
#include "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 <QMessageBox>
#include "image/checkimage.h"
#include "utils/utils.h"
#include <opencv2/objdetect.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <zbar.h>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow) {
ui->setupUi(this);
// this->setupStoresList();
}
MainWindow::~MainWindow() { delete ui; }
// void MainWindow::setupStoresList() {
// parser = *(new Parser());
// 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) {
// std::string checkContent = Net().fetch_check_data_from_ofdru(
// ui->fn_edit->text().toStdString(),
// ui->fd_edit->text().toStdString(),
// 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;
// }
// 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();
// }
// return;
// }
// std::wstring check_plaintext = s.toStdWString();
// parser.set_module(parser.search_modules()[0]);
// std::vector<Goods> c = parser.parse(check_plaintext);
// if (c.size() == 0) {
// QMessageBox infoDialog;
// infoDialog.setText(tr("An error has occured. Check was matched incorrectly. Vector sizes are different. Please, contact the developer."));
// infoDialog.setIcon(QMessageBox::Critical);
// infoDialog.setWindowTitle(tr("Error in parsing"));
// infoDialog.exec();
// return;
// }
// for (auto& g : c) {
// 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());
// connect(&dialog, &AdjustPictureDialog::decodedData, this, &MainWindow::onDecodedData);
// dialog.exec();
// ui->picture_ofd->setPixmap(QPixmap(filename));
// ui->picture_ofd->setScaledContents(true);
// }
// void MainWindow::onDecodedData(std::string data) {
// std::string delimiter = "&";
// std::vector<std::string> dataSplit = split(data, delimiter);
// std::cout << data << std::endl;
// 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");
// ui->dateTimeEdit->setDateTime(datetime);
// int type = std::stoi(split(dataSplit[5], "=")[1]);
// ui->fundIncomeCombo->setCurrentIndex(type - 1);
// std::string total = split(dataSplit[1], "=")[1];
// ui->total_edit->setText(QString::fromStdString(total));
// }
// void MainWindow::on_chooseImageButton_ocr_clicked()
// {
// QString filename = QFileDialog::getOpenFileName();
// if (filename == "") {
// QMessageBox infoDialog;
// infoDialog.setText(tr("Please, select a picture to scan"));
// infoDialog.setIcon(QMessageBox::Critical);
// 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());
// std::string parsed = i.parse_text();
// ui->picture_ocr->setPixmap(QPixmap(filename));
// ui->picture_ocr->setScaledContents(true);
// ui->checkContentFromImage->setPlainText(QString::fromStdString(parsed));
// }

View File

@@ -1,44 +1,25 @@
#ifndef MAINWINDOW_H #ifndef MAINWINDOW_H
#define MAINWINDOW_H #define MAINWINDOW_H
#include <QMainWindow> #include <QWidget>
#include <qevent.h>
#include <QtUiTools/quiloader.h>
#include "check/check.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();
Check get_check();
void onDecodedData(std::string);
std::string makeRequestToOfd(std::string captcha);
private slots:
void on_parseButton_clicked();
void on_storeType_currentIndexChanged(int index);
void on_preferencesButton_clicked();
void on_chooseImageButton_ofd_clicked();
void on_chooseImageButton_ocr_clicked();
private:
Ui::MainWindow *ui; Ui::MainWindow *ui;
private slots:
private:
}; };
#endif // MAINWINDOW_H #endif // MAINWINDOW_H

44
mainwindow.h.old Normal file
View File

@@ -0,0 +1,44 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "check/check.h"
#include "parser/parser.h"
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow {
Q_OBJECT
Check check;
Parser parser;
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
// void setupStoresList();
// Check get_check();
// void onDecodedData(std::string);
// std::string makeRequestToOfd(std::string captcha);
private slots:
// void on_parseButton_clicked();
// void on_storeType_currentIndexChanged(int index);
// void on_preferencesButton_clicked();
// void on_chooseImageButton_ofd_clicked();
// void on_chooseImageButton_ocr_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

7
media.qrc Normal file
View File

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

73
ocrscene.cpp Normal file
View File

@@ -0,0 +1,73 @@
#include "ocrscene.h"
#include "ui_ocrscene.h"
#include <QFileDialog>
#include <QMessageBox>
#include <outputdialog.h>
#include <image/checkimage.h>
#include <check/check.h>
OCRScene::OCRScene(QWidget *parent)
: QWidget(parent)
, ui(new Ui::OCRScene) {
ui->setupUi(this);
auto modules = parser.get_modules_names();
for (auto &module : modules) {
ui->store_combo_box->addItem(QString::fromStdString(module));
}
}
OCRScene::~OCRScene() {
delete ui;
}
void OCRScene::on_parse_button_clicked() {
std::wstring checkContent = ui->check_text_edit->toPlainText().toStdWString();
parser.set_module(parser.search_modules()[ui->store_combo_box->currentIndex()]);
std::vector<Goods> goods = parser.parse(checkContent);
if (goods.size() == 0) {
QMessageBox infoDialog;
infoDialog.setText(tr("An error has occured. Check was matched incorrectly. Vector sizes are different. Please, contact the developer."));
infoDialog.setIcon(QMessageBox::Critical);
infoDialog.setWindowTitle(tr("Error in parsing"));
infoDialog.exec();
return;
}
Check check;
check.add_goods(goods);
OutputDialog d(this, check);
d.show();
d.exec();
}
void OCRScene::on_choose_image_button_clicked() {
QString filename = QFileDialog::getOpenFileName();
if (filename == "") {
QMessageBox infoDialog;
infoDialog.setText(tr("Please, select a picture to scan"));
infoDialog.setIcon(QMessageBox::Critical);
infoDialog.setWindowTitle(tr("Picture was not selected"));
infoDialog.exec();
return;
}
std::string new_text = "Selected: " + filename.toStdString();
ui->path_to_image_label->setText(tr("Path to image: ")+ filename);
CheckImage i(filename.toStdString());
std::string parsed = i.parse_text();
ui->check_text_edit->setPlainText(QString::fromStdString(parsed));
}

29
ocrscene.h Normal file
View File

@@ -0,0 +1,29 @@
#ifndef OCRSCENE_H
#define OCRSCENE_H
#include "parser/parser.h"
#include <QWidget>
namespace Ui {
class OCRScene;
}
class OCRScene : public QWidget
{
Q_OBJECT
public:
explicit OCRScene(QWidget *parent = nullptr);
~OCRScene();
private slots:
void on_parse_button_clicked();
void on_choose_image_button_clicked();
private:
Ui::OCRScene *ui;
Parser parser;
};
#endif // OCRSCENE_H

216
ofdscene.cpp Normal file
View File

@@ -0,0 +1,216 @@
#include "ofdscene.h"
#include "ui_ofdscene.h"
#include "utils/utils.h"
#include <QFileDialog>
#include <QMessageBox>
#include <adjustpicturedialog.h>
#include <httplib.h>
#include <outputdialog.h>
#include <qpixmap.h>
#include <solvecaptchadialog.h>
#include <net/net.h>
#include <exceptions/ofdrequestexception.h>
#include <bits/basic_string.h>
#include <qrencode.h>
#include <bits/basic_string.h>
OFDScene::OFDScene(QWidget *parent)
: QWidget(parent)
, ui(new Ui::OFDScene) {
ui->setupUi(this);
QObject::connect(this, &OFDScene::httpErrorOccured, this, &OFDScene::notifyHttpServerFailure);
}
OFDScene::~OFDScene() {
delete ui;
}
void OFDScene::startHttpServer() {
std::string localIp = "";
try {
localIp = get_local_ip_address();
} catch(std::exception e) {
std::cerr << e.what() << std::endl;
return;
}
unsigned short number_of_retries = 0;
do {
if (number_of_retries == 10) {
emit httpErrorOccured();
return;
}
this->port = rand() % (65535 - 1024) + 1024;
std::string connectionString = "binaryeye://scan/?ret=http://"+ localIp +":"+ std::to_string(port) +"/?result={RESULT}";
server.Get("/", [&](const httplib::Request &req, httplib::Response &res){
std::map<std::string, std::string> paramsMap;
if (req.params.size() < 1) {
res.set_redirect(connectionString, 301);
std::cerr << "Too few params: " << req.params.size() << std::endl;
return;
}
std::string result = req.params.find("result")->second;
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 onDataDecode(paramsMap);
res.set_redirect(connectionString, 301);
});
std::cerr << "Listening on port: " << this->port << std::endl;
if (!server.listen("0.0.0.0", this->port)) {
std::cerr << "Random port seems to be occupied. Trying to generate another one" << std::endl;
number_of_retries ++;
continue;
}
} while(true);
}
void OFDScene::on_choose_image_button_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;
}
ui->info_label->setText(tr("Selected image: ") + filename);
AdjustPictureDialog dialog = AdjustPictureDialog(this, filename.toStdString());
connect(&dialog, &AdjustPictureDialog::decodedData, this, &OFDScene::onDataDecode);
dialog.exec();
}
void OFDScene::onDataDecode(std::map<std::string, std::string> data) {
ui->fn_line_edit->setText(QString::fromStdString(data["fn"]));
ui->fd_line_edit->setText(QString::fromStdString(data["i"]));
ui->fi_line_edit->setText(QString::fromStdString(data["fp"]));
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.
QDateTime datetime = QDateTime::fromString(extractedDateTime, "yyyyMMddThhmm");
if (datetime == QDateTime::fromString(extractedDateTime, "20000101T1200")) {
datetime = QDateTime::fromString(extractedDateTime, "yyyyMMddThhmmss");
}
ui->purchase_datetime_edit->setDateTime(datetime);
int type = std::stoi(data["n"]);
ui->operation_type_combo_box->setCurrentIndex(type - 1);
std::string total = data["s"];
ui->total_spin_box->setValue(std::stod(total));
}
void OFDScene::on_parse_button_clicked() {
Net net;
net.get_captcha_from_ofdru();
std::string solved_captcha = "";
bool success = true;
bool is_captcha_solved = true;
Check check;
do {
SolveCaptchaDialog dialog = SolveCaptchaDialog(this, &solved_captcha);
dialog.exec();
is_captcha_solved = true;
try {
std::string check_content = net.fetch_check_data_from_ofdru(
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 = OutputDialog(this, check);
d.exec();
}
}
void OFDScene::on_binary_eye_button_clicked() {
http_thread = new std::thread(&OFDScene::startHttpServer, this);
ui->binary_eye_button->setEnabled(false);
while (!server.is_running());
std::string localIp;
try {
localIp = get_local_ip_address();
} catch(std::exception e) {
std::cerr << e.what() << std::endl;
return;
}
std::string connectionString = "binaryeye://scan?ret=http://" + localIp + ":" + std::to_string(port) + "/?result={RESULT}";
generate_qr_code(connectionString);
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 OFDScene::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();
}
unsigned int OFDScene::getPort() {
return port;
}

43
ofdscene.h Normal file
View File

@@ -0,0 +1,43 @@
#ifndef OFDSCENE_H
#define OFDSCENE_H
#include <QWidget>
#include <httplib.h>
#include <thread>
namespace Ui {
class OFDScene;
}
class OFDScene : public QWidget
{
Q_OBJECT
public:
explicit OFDScene(QWidget *parent = nullptr);
~OFDScene();
void startHttpServer();
unsigned int getPort();
private slots:
void on_choose_image_button_clicked();
void onDataDecode(std::map<std::string, std::string>);
void on_parse_button_clicked();
void on_binary_eye_button_clicked();
void notifyHttpServerFailure();
signals:
void httpErrorOccured();
private:
Ui::OFDScene *ui;
std::thread *http_thread;
unsigned int port;
httplib::Server server;
};
#endif // OFDSCENE_H

View File

@@ -73,7 +73,7 @@
</rect> </rect>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>2</number> <number>1</number>
</property> </property>
<widget class="QWidget" name="Text"> <widget class="QWidget" name="Text">
<attribute name="title"> <attribute name="title">
@@ -110,7 +110,7 @@
<widget class="QPushButton" name="chooseImageButton_ocr"> <widget class="QPushButton" name="chooseImageButton_ocr">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>10</x>
<y>0</y> <y>0</y>
<width>80</width> <width>80</width>
<height>26</height> <height>26</height>
@@ -384,7 +384,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>817</width> <width>817</width>
<height>23</height> <height>33</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="menuchecks_parser"> <widget class="QMenu" name="menuchecks_parser">

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>111</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>111</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

@@ -31,7 +31,7 @@ StoreModule::StoreModule(std::string path) {
std::vector<std::string> StoreModule::parse_name(std::wstring str) { std::vector<std::string> StoreModule::parse_name(std::wstring str) {
std::vector<std::string> result; std::vector<std::string> result;
std::wregex r(this->goods_name_regex, std::regex::collate); std::wregex r(this->goods_name_regex, std::regex_constants::multiline);
for (std::wsregex_iterator it{str.begin(), str.end(), r}, end{}; it != end; for (std::wsregex_iterator it{str.begin(), str.end(), r}, end{}; it != end;
it++) { it++) {

View File

@@ -4,6 +4,7 @@
#include "../settings/settings.h" #include "../settings/settings.h"
#include "../utils/utils.h" #include "../utils/utils.h"
#include <iostream> #include <iostream>
#include <fstream>
#if __GNUC__ < 8 && __clang_major__ < 17 #if __GNUC__ < 8 && __clang_major__ < 17
# include <experimental/filesystem> # include <experimental/filesystem>
@@ -14,6 +15,27 @@
using namespace std::filesystem; using namespace std::filesystem;
#endif #endif
static void dumpVectorsToStdErr(std::vector<std::string> &goods_names, std::vector<std::string> &goods_prices, std::vector<std::string>& goods_quantities) {
std::cerr << goods_names.size() << " " << goods_prices.size() << " " << goods_quantities.size() << std::endl;
std::cerr << "Found goods names: ";
for (auto &goods_name : goods_names) {
std::cerr << goods_name << " ";
}
std::cerr << std::endl;
std::cerr << "Found goods prices: ";
for (auto &goods_price : goods_prices) {
std::cerr << goods_price << " ";
}
std::cerr << std::endl;
std::cerr << "Found goods names: ";
for (auto &goods_quantity : goods_quantities) {
std::cerr << goods_quantity << " ";
}
std::cerr << std::endl;
}
Parser::Parser() {} Parser::Parser() {}
std::vector<std::string> Parser::search_modules() { std::vector<std::string> Parser::search_modules() {
@@ -31,13 +53,28 @@ std::vector<std::string> Parser::search_modules() {
std::vector<std::string> modules_files; std::vector<std::string> modules_files;
for (auto file : directory_iterator(path)) { for (auto &file : directory_iterator(path)) {
modules_files.push_back(file.path()); modules_files.push_back(file.path());
} }
return modules_files; return modules_files;
} }
std::vector<std::string> Parser::get_modules_names() {
std::vector<std::string> modules = this->search_modules();
std::vector<std::string> names = {};
for (std::string &modulePath : modules) {
std::ifstream inputFile(modulePath);
nlohmann::json module = nlohmann::json::parse(inputFile);
std::string name = module["name"];
names.push_back(name);
}
return names;
}
void Parser::set_module(std::string path) { module = StoreModule(path); } void Parser::set_module(std::string path) { module = StoreModule(path); }
std::vector<Goods> Parser::parse(std::wstring check_plaintext) { std::vector<Goods> Parser::parse(std::wstring check_plaintext) {
@@ -53,6 +90,9 @@ std::vector<Goods> Parser::parse(std::wstring check_plaintext) {
if (goods_names.size() != goods_prices.size() || if (goods_names.size() != goods_prices.size() ||
goods_names.size() != goods_quantities.size() || goods_names.size() != goods_quantities.size() ||
goods_prices.size() != goods_quantities.size()) { goods_prices.size() != goods_quantities.size()) {
dumpVectorsToStdErr(goods_names, goods_prices, goods_quantities);
//Error. Amount of names, prices or quantities are not equal. That means, that some regex(es) has mismatched. //Error. Amount of names, prices or quantities are not equal. That means, that some regex(es) has mismatched.
return {}; return {};
} }

View File

@@ -15,6 +15,8 @@ public:
std::vector<std::string> search_modules(); std::vector<std::string> search_modules();
std::vector<std::string> get_modules_names();
std::vector<std::string> check_updates(); std::vector<std::string> check_updates();
void set_module(std::string); void set_module(std::string);

10
scenes.qrc Normal file
View File

@@ -0,0 +1,10 @@
<RCC>
<qresource prefix="/scenes">
<file>scenes/outputdialog.ui</file>
<file>scenes/emailtextscene.ui</file>
<file>scenes/ocrscene.ui</file>
<file>scenes/mainwindow.ui</file>
<file>scenes/ofdscene.ui</file>
<file>scenes/solvecaptchadialog.ui</file>
</qresource>
</RCC>

View File

@@ -61,10 +61,10 @@
<widget class="ImageRedactor" name="graphicsView"> <widget class="ImageRedactor" name="graphicsView">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>15</x> <x>5</x>
<y>41</y> <y>21</y>
<width>791</width> <width>801</width>
<height>391</height> <height>421</height>
</rect> </rect>
</property> </property>
</widget> </widget>
@@ -77,10 +77,7 @@
<customwidget> <customwidget>
<class>ImageRedactor</class> <class>ImageRedactor</class>
<extends>QGraphicsView</extends> <extends>QGraphicsView</extends>
<header>../../image_redactor/imageredactor.h</header> <header location="global">imageredactor.h</header>
<slots>
<slot>slot1()</slot>
</slots>
</customwidget> </customwidget>
</customwidgets> </customwidgets>
<resources/> <resources/>

80
scenes/emailtextscene.ui Normal file
View File

@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EmailTextScene</class>
<widget class="QWidget" name="EmailTextScene">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1077</width>
<height>608</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="0" colspan="3">
<widget class="QLabel" name="check_content_label">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Check content</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="3">
<widget class="QPushButton" name="parse_button">
<property name="text">
<string>Parse</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="store_label">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Store:</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="3">
<widget class="QTextEdit" name="check_content"/>
</item>
<item row="0" column="0">
<widget class="QPushButton" name="back_button">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Back</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="store_combo_box">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

121
scenes/mainwindow.ui Normal file
View File

@@ -0,0 +1,121 @@
<?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>693</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="2" column="0">
<layout class="QGridLayout" name="root_layout">
<property name="verticalSpacing">
<number>6</number>
</property>
<item row="0" column="1">
<widget class="QPushButton" name="ocr_button">
<property name="toolTip">
<string>Optical Character Recognition</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset>
<normaloff>:/icons/assets/icons/OCR.svg</normaloff>:/icons/assets/icons/OCR.svg</iconset>
</property>
<property name="iconSize">
<size>
<width>128</width>
<height>128</height>
</size>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QPushButton" name="text_from_email_button">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Text from E-Mail</string>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset>
<normaloff>:/icons/assets/icons/email-text.svg</normaloff>:/icons/assets/icons/email-text.svg</iconset>
</property>
<property name="iconSize">
<size>
<width>128</width>
<height>128</height>
</size>
</property>
<property name="autoRepeat">
<bool>false</bool>
</property>
<property name="autoExclusive">
<bool>false</bool>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<property name="default">
<bool>false</bool>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QPushButton" name="ofd_button">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset>
<normaloff>:/icons/assets/icons/OFD.svg</normaloff>:/icons/assets/icons/OFD.svg</iconset>
</property>
<property name="iconSize">
<size>
<width>128</width>
<height>128</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

127
scenes/ocrscene.ui Normal file
View File

@@ -0,0 +1,127 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>OCRScene</class>
<widget class="QWidget" name="OCRScene">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>992</width>
<height>634</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="topMargin">
<number>8</number>
</property>
<item row="1" column="2">
<widget class="QComboBox" name="store_combo_box">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="5" column="0" colspan="3">
<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="2" column="0" colspan="2">
<widget class="QPushButton" name="choose_image_button">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Choose</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="3">
<widget class="QPushButton" name="back_button">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Back</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="3">
<widget class="QLabel" name="instructions_label">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Recognized text will be shown below as soon as image will be processed. Please, edit it</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLabel" name="path_to_image_label">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Path to image:</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="3">
<widget class="QTextEdit" name="check_text_edit"/>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="store_label">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Store:</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

194
scenes/ofdscene.ui Normal file
View File

@@ -0,0 +1,194 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>OFDScene</class>
<widget class="QWidget" name="OFDScene">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>894</width>
<height>625</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="sizeConstraint">
<enum>QLayout::SizeConstraint::SetDefaultConstraint</enum>
</property>
<item row="8" column="0">
<widget class="QLabel" name="total_label">
<property name="text">
<string>Total</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QPushButton" name="back_button">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Back</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="or_label">
<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="8" column="2">
<widget class="QDoubleSpinBox" name="total_spin_box">
<property name="maximum">
<double>4294967296.000000000000000</double>
</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="6" column="0">
<widget class="QLabel" name="datetime_label">
<property name="text">
<string>Date and time of purchase</string>
</property>
</widget>
</item>
<item row="7" column="2">
<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="4" column="2">
<widget class="QLineEdit" name="fd_line_edit"/>
</item>
<item row="2" column="0" colspan="3">
<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="3" column="2">
<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="5" column="2">
<widget class="QLineEdit" name="fi_line_edit"/>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="binary_eye_button">
<property name="text">
<string>Use your phone as a QR code scanner</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="5" column="0">
<widget class="QLabel" name="fi_label">
<property name="text">
<string>FI (Fiscal Identifier)</string>
</property>
</widget>
</item>
<item row="6" column="2">
<widget class="QDateTimeEdit" name="purchase_datetime_edit"/>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="choose_image_button">
<property name="text">
<string>Choose image on your PC</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="9" column="0" colspan="3">
<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>
</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>

View File

@@ -50,7 +50,7 @@ Settings::Settings(std::string path) {
} }
})"_json; })"_json;
output << settings; output << settings.dump(4);
output.flush(); output.flush();
output.close(); output.close();
this->settings = settings; this->settings = settings;
@@ -70,7 +70,7 @@ void Settings::write_setting(std::string setting, std::string value) {
this->settings[setting] = value; this->settings[setting] = value;
output << this->settings; output << this->settings.dump(4);
} }
std::string Settings::get_setting(std::string setting) { std::string Settings::get_setting(std::string setting) {
return this->settings[setting]; return this->settings[setting];
@@ -93,5 +93,5 @@ void Settings::alter_setting(std::string setting, std::string value) {
void Settings::flush() { void Settings::flush() {
std::ofstream output(this->settings_file_path, std::fstream::trunc); std::ofstream output(this->settings_file_path, std::fstream::trunc);
output << this->settings; output << this->settings.dump(4);
} }

View File

@@ -3,6 +3,8 @@
#include "ui_settingsdialog.h" #include "ui_settingsdialog.h"
#include "utils/utils.h" #include "utils/utils.h"
#include <QMessageBox>
SettingsDialog::SettingsDialog(QWidget *parent) SettingsDialog::SettingsDialog(QWidget *parent)
: QDialog(parent), ui(new Ui::settingsdialog), : QDialog(parent), ui(new Ui::settingsdialog),
settings(Settings(get_path_relative_to_home( settings(Settings(get_path_relative_to_home(
@@ -32,6 +34,19 @@ 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;
if (!this->settings.get_all_settings().contains("language")) {
currentLanguageIndex = ui->languageComboBox->findText(QLocale::system().name());
if (currentLanguageIndex < 0) {
currentLanguageIndex = ui->languageComboBox->findText("en_US");
}
} else {
currentLanguageIndex = ui->languageComboBox->findText(QString::fromStdString(this->settings.get_all_settings()["language"]));
}
ui->languageComboBox->setCurrentIndex(currentLanguageIndex);
} }
SettingsDialog::~SettingsDialog() { delete ui; } SettingsDialog::~SettingsDialog() { delete ui; }
@@ -121,4 +136,19 @@ 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) {
if (this->settings.get_all_settings().contains("language")) {
if (changed == QString::fromStdString(this->settings.get_all_settings()["language"])) return;
} else {
if (changed == QLocale::system().name()) return;
}
this->settings.get_all_settings()["language"] = changed.toStdString();
QMessageBox infoDialog;
infoDialog.setText(tr("You need to restart program to apply language changes"));
infoDialog.setIcon(QMessageBox::Information);
infoDialog.setWindowTitle(tr("Restart required"));
infoDialog.exec();
}

View File

@@ -52,6 +52,8 @@ private slots:
void on_buttonBox_rejected(); void on_buttonBox_rejected();
void on_languageComboBox_currentTextChanged(const QString &arg1);
private: private:
Ui::settingsdialog *ui; Ui::settingsdialog *ui;
}; };

View File

@@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>599</width> <width>599</width>
<height>727</height> <height>799</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@@ -17,16 +17,16 @@
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>310</x> <x>310</x>
<y>690</y> <y>740</y>
<width>251</width> <width>251</width>
<height>32</height> <height>32</height>
</rect> </rect>
</property> </property>
<property name="orientation"> <property name="orientation">
<enum>Qt::Orientation::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
<property name="standardButtons"> <property name="standardButtons">
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Save</set> <set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
</property> </property>
</widget> </widget>
<widget class="QScrollArea" name="scrollArea"> <widget class="QScrollArea" name="scrollArea">
@@ -35,7 +35,7 @@
<x>10</x> <x>10</x>
<y>0</y> <y>0</y>
<width>541</width> <width>541</width>
<height>661</height> <height>741</height>
</rect> </rect>
</property> </property>
<property name="widgetResizable"> <property name="widgetResizable">
@@ -47,7 +47,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>539</width> <width>539</width>
<height>659</height> <height>739</height>
</rect> </rect>
</property> </property>
<widget class="QWidget" name="gridLayoutWidget"> <widget class="QWidget" name="gridLayoutWidget">
@@ -56,16 +56,126 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>531</width> <width>531</width>
<height>651</height> <height>731</height>
</rect> </rect>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="11" column="1"> <item row="15" column="1">
<widget class="QLineEdit" name="goodsNetWeightAliasEdit"/> <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>
<item row="1" column="1"> <item row="1" column="1">
<widget class="QLineEdit" name="storesModulesDirEdit"/> <widget class="QLineEdit" name="storesModulesDirEdit"/>
</item> </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"> <item row="4" column="0">
<widget class="QLabel" name="label_9"> <widget class="QLabel" name="label_9">
<property name="text"> <property name="text">
@@ -73,6 +183,51 @@
</property> </property>
</widget> </widget>
</item> </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"> <item row="7" column="0">
<widget class="QLabel" name="label_12"> <widget class="QLabel" name="label_12">
<property name="text"> <property name="text">
@@ -87,159 +242,25 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="13" column="1"> <item row="16" column="0">
<widget class="QLineEdit" name="goodsTotalAliasEdit"/> <widget class="QLabel" name="label_4">
</item>
<item row="14" column="0">
<widget class="QLabel" name="label_2">
<property name="text"> <property name="text">
<string>Print header</string> <string>TextLabel</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="11" column="0"> <item row="16" column="1">
<widget class="QLabel" name="label_16"> <widget class="QComboBox" name="languageComboBox">
<property name="text"> <item>
<string>Goods net weight alias</string> <property name="text">
</property> <string>en_US</string>
</widget> </property>
</item> </item>
<item row="3" column="0"> <item>
<widget class="QLabel" name="label_8"> <property name="text">
<property name="text"> <string>ru_RU</string>
<string>Stores modules url</string> </property>
</property> </item>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="storesModulesURLEdit"/>
</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="5" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Goods name alias</string>
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="QSpinBox" name="goodsTotalPositionSpin"/>
</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="1" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Stores modules directory</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="goodsNameAliasEdit"/>
</item>
<item row="10" column="1">
<widget class="QSpinBox" name="goodsNetWeightPositionSpin"/>
</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="4" column="1">
<widget class="QSpinBox" name="goodsNamePositionSpin"/>
</item>
<item row="9" column="1">
<widget class="QLineEdit" name="goodsQuantityAliasEdit"/>
</item>
<item row="7" column="1">
<widget class="QLineEdit" name="goodsPricePerUnitAliasEdit"/>
</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="10" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Goods net weight position</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>OFD modules url</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="OFDModulesDirEdit"/>
</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="8" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Goods quantity position</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="OFDModulesURLEdit"/>
</item>
<item row="8" column="1">
<widget class="QSpinBox" name="goodsQuantityPositionSpin"/>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="OFDModulesDirChooseButton">
<property name="text">
<string>Choose</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QSpinBox" name="goodsPricePerUnitPositionSpin"/>
</item>
<item row="15" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Print total</string>
</property>
</widget>
</item>
<item row="14" column="1">
<widget class="QCheckBox" name="printHeaderCheckBox">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="15" column="1">
<widget class="QCheckBox" name="printTotalCheckBox">
<property name="text">
<string/>
</property>
</widget> </widget>
</item> </item>
</layout> </layout>

6
translations.qrc Normal file
View File

@@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/translation">
<file>en_US.qm</file>
<file>ru_RU.qm</file>
</qresource>
</RCC>

View File

@@ -1,404 +1,668 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS> <!DOCTYPE TS>
<TS version="2.1"> <TS version="2.1" language="en_US">
<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 type="unfinished"></translation> <translation>Dialog</translation>
</message> </message>
<message> <message>
<location filename="../adjustpicturedialog.ui" line="58"/> <location filename="../scenes/adjustpicturedialog.ui" line="58"/>
<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 type="unfinished"></translation> <translation>Please, zoom to qr code and adjust contrast so that qr code looks sharp</translation>
</message> </message>
<message> <message>
<location filename="../adjustpicturedialog.cpp" line="39"/> <location filename="../adjustpicturedialog.cpp" line="39"/>
<source>QR code was not detected on that image. Please edit it again or enter data manually</source> <source>QR code was not detected on that image. Please edit it again or enter data manually</source>
<translation type="unfinished"></translation> <translation>QR code was not detected on that image. Please edit it again or enter data manually</translation>
</message> </message>
<message> <message>
<location filename="../adjustpicturedialog.cpp" line="41"/> <location filename="../adjustpicturedialog.cpp" line="41"/>
<source>No QR code</source> <source>No QR code</source>
<translation type="unfinished"></translation> <translation>No QR code</translation>
</message>
</context>
<context>
<name>EmailTextScene</name>
<message>
<location filename="../scenes/emailtextscene.ui" line="14"/>
<source>Form</source>
<translation>Form</translation>
</message>
<message>
<source>Store type</source>
<translation type="obsolete">Store type</translation>
</message>
<message>
<location filename="../scenes/emailtextscene.ui" line="26"/>
<source>Check content</source>
<translation>Check content</translation>
</message>
<message>
<location filename="../scenes/emailtextscene.ui" line="33"/>
<source>Parse</source>
<translation>Parse</translation>
</message>
<message>
<location filename="../scenes/emailtextscene.ui" line="46"/>
<source>Store:</source>
<translation>Store:</translation>
</message>
<message>
<location filename="../scenes/emailtextscene.ui" line="62"/>
<source>Back</source>
<translation>Back</translation>
</message>
<message>
<location filename="../emailtextscene.cpp" line="31"/>
<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>
</message>
<message>
<location filename="../emailtextscene.cpp" line="33"/>
<source>Error in parsing</source>
<translation>Error in parsing</translation>
</message> </message>
</context> </context>
<context> <context>
<name>MainWindow</name> <name>MainWindow</name>
<message> <message>
<location filename="../mainwindow.ui" line="14"/>
<source>MainWindow</source> <source>MainWindow</source>
<translation type="unfinished"></translation> <translation type="vanished">Главное окно</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="37"/>
<source>Store type</source> <source>Store type</source>
<translation type="unfinished"></translation> <translation type="vanished">Store type</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="50"/>
<source>Parse</source> <source>Parse</source>
<translation type="unfinished"></translation> <translation type="vanished">Parse</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="63"/>
<source>Preferences</source> <source>Preferences</source>
<translation type="unfinished"></translation> <translation type="vanished">Preferences</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="80"/>
<source>Text</source> <source>Text</source>
<translation type="unfinished"></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 type="unfinished"></translation> <translation type="vanished">Check content</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="108"/>
<source>OCR</source> <source>OCR</source>
<translation type="unfinished"></translation> <translatorcomment>OCR = Optical Character Recognition</translatorcomment>
<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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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>
<translation type="unfinished"></translation> <translatorcomment>OFD = Оператор Фискальных Данных</translatorcomment>
<translation type="vanished">OFD</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="226"/>
<source>0000000000000000</source> <source>0000000000000000</source>
<translation type="unfinished"></translation> <translation type="vanished">0000000000000000</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="245"/>
<source>FN (Fiscal Number)</source> <source>FN (Fiscal Number)</source>
<translation type="unfinished"></translation> <translatorcomment>FN = Фискальный Номер</translatorcomment>
<translation type="vanished">FN (Fiscal Number)</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="264"/>
<source>FD (Fiscal Document)</source> <source>FD (Fiscal Document)</source>
<translation type="unfinished"></translation> <translatorcomment>FD = Фискальный Документ</translatorcomment>
<translation type="vanished">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 type="unfinished"></translation> <translation type="vanished">000000000</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="296"/>
<source>FI (Fiscal Identifier)</source> <source>FI (Fiscal Identifier)</source>
<translation type="unfinished"></translation> <translatorcomment>FI = Фискальный Признак</translatorcomment>
<translation type="vanished">FI (Fiscal Identifier)</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="333"/>
<source>Funds income</source> <source>Funds income</source>
<translation type="unfinished"></translation> <translatorcomment>Приход средств</translatorcomment>
<translation type="vanished">Funds income</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="338"/>
<source>Funds return</source> <source>Funds return</source>
<translation type="unfinished"></translation> <translatorcomment>Возврат средств</translatorcomment>
<translation type="vanished">Funds return</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="343"/>
<source>Funds spend</source> <source>Funds spend</source>
<translation type="unfinished"></translation> <translatorcomment>Расход средств</translatorcomment>
<translation type="vanished">Funds spend</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="348"/>
<source>Spends return</source> <source>Spends return</source>
<translation type="unfinished"></translation> <translatorcomment>Возврат расхода</translatorcomment>
<translation type="vanished">Spends return</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="375"/>
<source>Total</source> <source>Total</source>
<translation type="unfinished"></translation> <translation type="vanished">Total</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="392"/>
<source>checks parser</source> <source>checks parser</source>
<translation type="unfinished"></translation> <translation type="vanished">checks parser</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="85"/>
<source>Captcha was not solved correctly!</source> <source>Captcha was not solved correctly!</source>
<translation type="unfinished"></translation> <translation type="vanished">Captcha was not solved correctly!</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="87"/>
<source>Captcha is incorrect</source> <source>Captcha is incorrect</source>
<translation type="unfinished"></translation> <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>
<message> <message>
<location filename="../mainwindow.cpp" line="92"/>
<source>Check not found. Please, ensure correctness of entered data.</source> <source>Check not found. Please, ensure correctness of entered data.</source>
<translation type="unfinished"></translation> <translation type="vanished">Check not found. Please, ensure correctness of entered data.</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="94"/> <source>An error has occured. Check was matched incorrectly. Vector sizes are different. Please, contact the developer.</source>
<source>Check was not found</source> <translation type="vanished">An error has occured. Check was matched incorrectly. Vector sizes are different. Please, contact the developer.</translation>
<translation type="unfinished"></translation> </message>
<message>
<source>Error in parsing</source>
<translation type="vanished">Error in parsing</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="145"/>
<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 type="unfinished"></translation> <translation type="vanished">Please, select a picture where QR code that contains info about check is present</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="147"/>
<location filename="../mainwindow.cpp" line="193"/>
<source>Picture was not selected</source> <source>Picture was not selected</source>
<translation type="vanished">Picture was not selected</translation>
</message>
<message>
<source>Please, select a picture to scan</source>
<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>
<location filename="../scenes/mainwindow.ui" line="37"/>
<source>Optical Character Recognition</source>
<translation>Optical Character Recognition</translation>
</message>
<message>
<location filename="../scenes/mainwindow.ui" line="63"/>
<source>Text from E-Mail</source>
<translation>Text from E-Mail</translation>
</message>
</context>
<context>
<name>OCRScene</name>
<message>
<location filename="../scenes/ocrscene.ui" line="20"/>
<source>Form</source>
<translation>Form</translation>
</message>
<message>
<location filename="../scenes/ocrscene.ui" line="64"/>
<source>Choose</source>
<translation>Choose</translation>
</message>
<message>
<location filename="../scenes/ocrscene.ui" line="103"/>
<source>Path to image:</source>
<translation>Path to image:</translation>
</message>
<message>
<location filename="../scenes/ocrscene.ui" line="119"/>
<source>Store:</source>
<translation>Store:</translation>
</message>
<message>
<location filename="../scenes/ocrscene.ui" line="90"/>
<source>Recognized text will be shown below as soon as image will be processed. Please, edit it</source>
<translation>Recognized text will be shown below as soon as image will be processed. Please, edit it</translation>
</message>
<message>
<location filename="../scenes/ocrscene.ui" line="77"/>
<source>Back</source>
<translation>Back</translation>
</message>
<message>
<location filename="../scenes/ocrscene.ui" line="45"/>
<source>Parse</source>
<translation>Parse</translation>
</message>
<message>
<location filename="../ocrscene.cpp" line="36"/>
<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>
</message>
<message>
<location filename="../ocrscene.cpp" line="38"/>
<source>Error in parsing</source>
<translation>Error in parsing</translation>
</message>
<message>
<location filename="../ocrscene.cpp" line="56"/>
<source>Please, select a picture to scan</source>
<translation>Please, select a picture to scan</translation>
</message>
<message>
<location filename="../ocrscene.cpp" line="58"/>
<source>Picture was not selected</source>
<translation>Picture was not selected</translation>
</message>
<message>
<location filename="../ocrscene.cpp" line="64"/>
<source>Path to image: </source>
<translation>Path to image: </translation>
</message>
</context>
<context>
<name>OFDScene</name>
<message>
<location filename="../scenes/ofdscene.ui" line="14"/>
<source>Form</source>
<translation>Form</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="23"/>
<source>Total</source>
<translation>Total</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="36"/>
<source>Back</source>
<translation>Back</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="49"/>
<source>or</source>
<translation>or</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="69"/>
<source>FD (Fiscal Document)</source>
<translation>FD (Fiscal Document)</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="76"/>
<source>Date and time of purchase</source>
<translation>Date and time of purchase</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="84"/>
<source>Funds income</source>
<translation>Funds income</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="89"/>
<source>Funds return</source>
<translation>Funds return</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="94"/>
<source>Funds spend</source>
<translation>Funds spend</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="99"/>
<source>Spends return</source>
<translation>Spends return</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="136"/>
<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/ofdscene.ui" line="149"/>
<source>FN (Fiscal Number)</source>
<translation>FN (Fiscal Number)</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="156"/>
<source>FI (Fiscal Identifier)</source>
<translation>FI (Fiscal Identifier)</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="166"/>
<source>Choose image on your PC</source>
<translation>Choose image on your PC</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="173"/>
<source>Operation type</source>
<translation>Operation type</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="186"/>
<source>Parse</source>
<translation>Parse</translation>
</message>
<message>
<location filename="../ofdscene.cpp" line="205"/>
<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="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="191"/> <location filename="../ofdscene.cpp" line="207"/>
<source>Please, select a picture to scan</source> <source>Could not start http server.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<location filename="../ofdscene.cpp" line="84"/>
<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>
</message>
<message>
<location filename="../ofdscene.cpp" line="86"/>
<source>Picture was not selected</source>
<translation>Picture was not selected</translation>
</message>
<message>
<location filename="../ofdscene.cpp" line="91"/>
<source>Selected image: </source>
<translation>Selected image: </translation>
</message>
<message>
<location filename="../ofdscene.cpp" line="150"/>
<source>Captcha was not solved correctly!</source>
<translation>Captcha was not solved correctly!</translation>
</message>
<message>
<location filename="../ofdscene.cpp" line="152"/>
<source>Captcha is incorrect</source>
<translation>Captcha is incorrect</translation>
</message>
<message>
<location filename="../ofdscene.cpp" line="157"/>
<source>Internal server error. Please, try again later.</source>
<translation>Internal server error. Please, try again later.</translation>
</message>
<message>
<location filename="../ofdscene.cpp" line="159"/>
<source>Internal server error</source>
<translation>Internal server error</translation>
</message>
<message>
<location filename="../ofdscene.cpp" line="164"/>
<source>Check not found. Please, ensure correctness of entered data.</source>
<translation>Check not found. Please, ensure correctness of entered data.</translation>
</message>
<message>
<location filename="../ofdscene.cpp" line="166"/>
<source>Check was not found</source>
<translation>Check was not found</translation>
</message>
<message>
<location filename="../ofdscene.cpp" line="198"/>
<source>QR code for binaryeye to connect</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ofdscene.cpp" line="199"/>
<source>I&apos;ve scanned</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>123 123</source>
<translation type="obsolete">123 123</translation>
</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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></translation> <translation>Print total</translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<source>You need to restart program to apply language changes</source>
<translation type="vanished">You need to restart program to apply language changes</translation>
</message>
<message>
<source>Restart required</source>
<translation type="vanished">Restart required</translation>
</message> </message>
</context> </context>
<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 type="unfinished"></translation> <translation>Dialog</translation>
</message> </message>
<message> <message>
<location filename="../solvecaptchadialog.cpp" line="23"/> <location filename="../solvecaptchadialog.cpp" line="23"/>
<source>Please, enter a valid captcha</source> <source>Please, enter a valid captcha</source>
<translation type="unfinished"></translation> <translation>Please, enter a valid captcha</translation>
</message> </message>
<message> <message>
<location filename="../solvecaptchadialog.cpp" line="25"/> <location filename="../solvecaptchadialog.cpp" line="25"/>
<source>No captcha</source> <source>No captcha</source>
<translation type="unfinished"></translation> <translation>No captcha</translation>
</message> </message>
</context> </context>
<context> <context>
<name>settingsdialog</name> <name>settingsdialog</name>
<message> <message>
<location filename="../settingsdialog.ui" line="14"/>
<source>Dialog</source> <source>Dialog</source>
<translation type="unfinished"></translation> <translation type="vanished">Dialog</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="72"/>
<source>Goods name position</source> <source>Goods name position</source>
<translation type="unfinished"></translation> <translation type="vanished">Goods name position</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="79"/>
<source>Goods price per unit alias</source> <source>Goods price per unit alias</source>
<translation type="unfinished"></translation> <translation type="vanished">Goods price per unit alias</translation>
</message>
<message>
<source>TextLabel</source>
<translation type="vanished">Language</translation>
</message>
<message>
<source>en_US</source>
<translation type="vanished">en_US</translation>
</message>
<message>
<source>ru_RU</source>
<translation type="vanished">ru_RU</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="86"/>
<location filename="../settingsdialog.ui" line="217"/>
<source>Choose</source> <source>Choose</source>
<translation type="unfinished"></translation> <translation type="vanished">Choose</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="96"/>
<source>Print header</source> <source>Print header</source>
<translation type="unfinished"></translation> <translation type="vanished">Print header</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="103"/>
<source>Goods net weight alias</source> <source>Goods net weight alias</source>
<translation type="unfinished"></translation> <translation type="vanished">Goods net weight alias</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="110"/>
<source>Stores modules url</source> <source>Stores modules url</source>
<translation type="unfinished"></translation> <translation type="vanished">Stores modules url</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="120"/>
<source>Goods total alias</source> <source>Goods total alias</source>
<translation type="unfinished"></translation> <translation type="vanished">Goods total alias</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="127"/>
<source>Goods name alias</source> <source>Goods name alias</source>
<translation type="unfinished"></translation> <translation type="vanished">Goods name alias</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="137"/>
<source>Goods quantity alias</source> <source>Goods quantity alias</source>
<translation type="unfinished"></translation> <translation type="vanished">Goods quantity alias</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="144"/>
<source>Stores modules directory</source> <source>Stores modules directory</source>
<translation type="unfinished"></translation> <translation type="vanished">Stores modules directory</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="157"/>
<source>OFD modules directory</source> <source>OFD modules directory</source>
<translation type="unfinished"></translation> <translation type="vanished">OFD modules directory</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="173"/>
<source>Goods price per unit position</source> <source>Goods price per unit position</source>
<translation type="unfinished"></translation> <translation type="vanished">Goods price per unit position</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="180"/>
<source>Goods net weight position</source> <source>Goods net weight position</source>
<translation type="unfinished"></translation> <translation type="vanished">Goods net weight position</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="187"/>
<source>OFD modules url</source> <source>OFD modules url</source>
<translation type="unfinished"></translation> <translation type="vanished">OFD modules url</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="197"/>
<source>Goods total position</source> <source>Goods total position</source>
<translation type="unfinished"></translation> <translation type="vanished">Goods total position</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="204"/>
<source>Goods quantity position</source> <source>Goods quantity position</source>
<translation type="unfinished"></translation> <translation type="vanished">Goods quantity position</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="227"/>
<source>Print total</source> <source>Print total</source>
<translation type="unfinished"></translation> <translation type="vanished">Print total</translation>
</message> </message>
</context> </context>
</TS> </TS>

View File

@@ -4,401 +4,665 @@
<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 type="unfinished"></translation> <translation>Диалог</translation>
</message> </message>
<message> <message>
<location filename="../adjustpicturedialog.ui" line="58"/> <location filename="../scenes/adjustpicturedialog.ui" line="58"/>
<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 type="unfinished"></translation> <translation>Пожалуйста, приблизьте QR код и настройте контраст, чтобы он читался</translation>
</message> </message>
<message> <message>
<location filename="../adjustpicturedialog.cpp" line="39"/> <location filename="../adjustpicturedialog.cpp" line="39"/>
<source>QR code was not detected on that image. Please edit it again or enter data manually</source> <source>QR code was not detected on that image. Please edit it again or enter data manually</source>
<translation type="unfinished"></translation> <translation>QR код не найден на этом изображении. Пожалуйста, попытайтесь снова или введите данные вручную</translation>
</message> </message>
<message> <message>
<location filename="../adjustpicturedialog.cpp" line="41"/> <location filename="../adjustpicturedialog.cpp" line="41"/>
<source>No QR code</source> <source>No QR code</source>
<translation type="unfinished"></translation> <translation>QR код не найден</translation>
</message>
</context>
<context>
<name>EmailTextScene</name>
<message>
<location filename="../scenes/emailtextscene.ui" line="14"/>
<source>Form</source>
<translation>Форма</translation>
</message>
<message>
<source>Store type</source>
<translation type="obsolete">Магазин</translation>
</message>
<message>
<location filename="../scenes/emailtextscene.ui" line="26"/>
<source>Check content</source>
<translation>Контент чека</translation>
</message>
<message>
<location filename="../scenes/emailtextscene.ui" line="33"/>
<source>Parse</source>
<translation>Парсить</translation>
</message>
<message>
<location filename="../scenes/emailtextscene.ui" line="46"/>
<source>Store:</source>
<translation>Магазин:</translation>
</message>
<message>
<location filename="../scenes/emailtextscene.ui" line="62"/>
<source>Back</source>
<translation>Назад</translation>
</message>
<message>
<location filename="../emailtextscene.cpp" line="31"/>
<source>An error has occured. Check was matched incorrectly. Vector sizes are different. Please, contact the developer.</source>
<translation>Произошла ошибка. Чек был прочитан неверно. Размеры векторов различаются. Пожалуйста, сообщите об этом разработчику.</translation>
</message>
<message>
<location filename="../emailtextscene.cpp" line="33"/>
<source>Error in parsing</source>
<translation>Ошибка в парсинге</translation>
</message> </message>
</context> </context>
<context> <context>
<name>MainWindow</name> <name>MainWindow</name>
<message> <message>
<location filename="../mainwindow.ui" line="14"/>
<source>MainWindow</source> <source>MainWindow</source>
<translation type="unfinished"></translation> <translation type="vanished">ГлавноеОкно</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="37"/>
<source>Store type</source> <source>Store type</source>
<translation type="unfinished"></translation> <translation type="vanished">Магазин</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="50"/>
<source>Parse</source> <source>Parse</source>
<translation type="unfinished"></translation> <translation type="vanished">Парсить</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="63"/>
<source>Preferences</source> <source>Preferences</source>
<translation type="unfinished"></translation> <translation type="vanished">Настройки</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="80"/>
<source>Text</source> <source>Text</source>
<translation type="unfinished"></translation> <translation type="vanished">Текст</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="92"/>
<source>Check content</source> <source>Check content</source>
<translation type="unfinished"></translation> <translation type="vanished">Контент чека</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="108"/>
<source>OCR</source> <source>OCR</source>
<translation type="unfinished"></translation> <translatorcomment>Оптическое Распознавание Символов</translatorcomment>
<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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></translation> <translation type="vanished">Ниже приведён распознанный текст. Пожалуйста, отредактируйте его:</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="175"/>
<source>OFD</source> <source>OFD</source>
<translation type="unfinished"></translation> <translatorcomment>Оператор Фискальных Данных</translatorcomment>
<translation type="vanished">ОФД</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="226"/>
<source>0000000000000000</source> <source>0000000000000000</source>
<translation type="unfinished"></translation> <translation type="vanished">0000000000000000</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="245"/>
<source>FN (Fiscal Number)</source> <source>FN (Fiscal Number)</source>
<translation type="unfinished"></translation> <translatorcomment>Фискальный Норма</translatorcomment>
<translation type="vanished">ФН</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="264"/>
<source>FD (Fiscal Document)</source> <source>FD (Fiscal Document)</source>
<translation type="unfinished"></translation> <translatorcomment>Фискальный Документ</translatorcomment>
<translation type="vanished">ФД</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="277"/>
<location filename="../mainwindow.ui" line="309"/>
<source>0000000000</source> <source>0000000000</source>
<translation type="unfinished"></translation> <translation type="vanished">000000000</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="296"/>
<source>FI (Fiscal Identifier)</source> <source>FI (Fiscal Identifier)</source>
<translation type="unfinished"></translation> <translatorcomment>Фискальный Признак</translatorcomment>
<translation type="vanished">ФП</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="333"/>
<source>Funds income</source> <source>Funds income</source>
<translation type="unfinished"></translation> <translation type="vanished">Приход средств</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="338"/>
<source>Funds return</source> <source>Funds return</source>
<translation type="unfinished"></translation> <translation type="vanished">Возврат средств</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="343"/>
<source>Funds spend</source> <source>Funds spend</source>
<translation type="unfinished"></translation> <translation type="vanished">Расход средств</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="348"/>
<source>Spends return</source> <source>Spends return</source>
<translation type="unfinished"></translation> <translation type="vanished">Возврат расхода</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="375"/>
<source>Total</source> <source>Total</source>
<translation type="unfinished"></translation> <translation type="vanished">Итого</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.ui" line="392"/>
<source>checks parser</source> <source>checks parser</source>
<translation type="unfinished"></translation> <translation type="vanished">Парсер чеков</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="85"/>
<source>Captcha was not solved correctly!</source> <source>Captcha was not solved correctly!</source>
<translation type="unfinished"></translation> <translation type="vanished">Капча была решена неверно!</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="87"/>
<source>Captcha is incorrect</source> <source>Captcha is incorrect</source>
<translation type="unfinished"></translation> <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>
<message> <message>
<location filename="../mainwindow.cpp" line="92"/>
<source>Check not found. Please, ensure correctness of entered data.</source> <source>Check not found. Please, ensure correctness of entered data.</source>
<translation type="unfinished"></translation> <translation type="vanished">Чек не найден. Пожалуйста, убедитесь в правильности введённых данных.</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="94"/>
<source>Check was not found</source> <source>Check was not found</source>
<translation type="unfinished"></translation> <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>
<message> <message>
<location filename="../mainwindow.cpp" line="145"/>
<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 type="unfinished"></translation> <translation type="vanished">Пожалуйста, выберете изображение, содержащее QR код с информацией о чеке</translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="147"/>
<location filename="../mainwindow.cpp" line="193"/>
<source>Picture was not selected</source> <source>Picture was not selected</source>
<translation type="vanished">Изображение не было выбрано</translation>
</message>
<message>
<source>Please, select a picture to scan</source>
<translation type="vanished">Пожалуйста, выберете изображение для сканирования</translation>
</message>
<message>
<location filename="../scenes/mainwindow.ui" line="26"/>
<source>Form</source>
<translation>Форма</translation>
</message>
<message>
<location filename="../scenes/mainwindow.ui" line="37"/>
<source>Optical Character Recognition</source>
<translation>Оптическое распознавание символов</translation>
</message>
<message>
<location filename="../scenes/mainwindow.ui" line="63"/>
<source>Text from E-Mail</source>
<translation>Текст из электронного письма</translation>
</message>
</context>
<context>
<name>OCRScene</name>
<message>
<location filename="../scenes/ocrscene.ui" line="20"/>
<source>Form</source>
<translation>Форма</translation>
</message>
<message>
<location filename="../scenes/ocrscene.ui" line="64"/>
<source>Choose</source>
<translation>Выбрать</translation>
</message>
<message>
<location filename="../scenes/ocrscene.ui" line="103"/>
<source>Path to image:</source>
<translation>Путь к изображению:</translation>
</message>
<message>
<location filename="../scenes/ocrscene.ui" line="119"/>
<source>Store:</source>
<translation>Магазин:</translation>
</message>
<message>
<location filename="../scenes/ocrscene.ui" line="90"/>
<source>Recognized text will be shown below as soon as image will be processed. Please, edit it</source>
<translation>Распознанный текст будет показан ниже как только изображение обработается. Пожалуйста, отредактируйте</translation>
</message>
<message>
<location filename="../scenes/ocrscene.ui" line="77"/>
<source>Back</source>
<translation>Назад</translation>
</message>
<message>
<location filename="../scenes/ocrscene.ui" line="45"/>
<source>Parse</source>
<translation>Парсить</translation>
</message>
<message>
<location filename="../ocrscene.cpp" line="36"/>
<source>An error has occured. Check was matched incorrectly. Vector sizes are different. Please, contact the developer.</source>
<translation>Произошла ошибка. Чек был прочитан неверно. Размеры векторов различаются. Пожалуйста, сообщите об этом разработчику.</translation>
</message>
<message>
<location filename="../ocrscene.cpp" line="38"/>
<source>Error in parsing</source>
<translation>Ошибка в парсинге</translation>
</message>
<message>
<location filename="../ocrscene.cpp" line="56"/>
<source>Please, select a picture to scan</source>
<translation>Пожалуйста, выберете изображение для сканирования</translation>
</message>
<message>
<location filename="../ocrscene.cpp" line="58"/>
<source>Picture was not selected</source>
<translation>Изображение не было выбрано</translation>
</message>
<message>
<location filename="../ocrscene.cpp" line="64"/>
<source>Path to image: </source>
<translation>Путь к изображению: </translation>
</message>
</context>
<context>
<name>OFDScene</name>
<message>
<location filename="../scenes/ofdscene.ui" line="14"/>
<source>Form</source>
<translation>Форма</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="23"/>
<source>Total</source>
<translation>Итого</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="36"/>
<source>Back</source>
<translation>Назад</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="49"/>
<source>or</source>
<translation>или</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="69"/>
<source>FD (Fiscal Document)</source>
<translation>ФД</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="76"/>
<source>Date and time of purchase</source>
<translation>Дата и время покупки</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="84"/>
<source>Funds income</source>
<translation>Приход средств</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="89"/>
<source>Funds return</source>
<translation>Возврат средств</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="94"/>
<source>Funds spend</source>
<translation>Расход средств</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="99"/>
<source>Spends return</source>
<translation>Возврат расхода</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="136"/>
<source>Use your phone as a QR code scanner</source>
<translation>Использовать телефон как сканнер QR</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="149"/>
<source>FN (Fiscal Number)</source>
<translation>ФН</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="156"/>
<source>FI (Fiscal Identifier)</source>
<translation>ФП</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="166"/>
<source>Choose image on your PC</source>
<translation>Выбрать изображение на компьютере</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="173"/>
<source>Operation type</source>
<translation>Тип операции</translation>
</message>
<message>
<location filename="../scenes/ofdscene.ui" line="186"/>
<source>Parse</source>
<translation>Парсить</translation>
</message>
<message>
<location filename="../ofdscene.cpp" line="205"/>
<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="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../mainwindow.cpp" line="191"/> <location filename="../ofdscene.cpp" line="207"/>
<source>Please, select a picture to scan</source> <source>Could not start http server.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<location filename="../ofdscene.cpp" line="84"/>
<source>Please, select a picture where QR code that contains info about check is present</source>
<translation>Пожалуйста, выберете изображение, содержащее QR код с информацией о чеке</translation>
</message>
<message>
<location filename="../ofdscene.cpp" line="86"/>
<source>Picture was not selected</source>
<translation>Изображение не было выбрано</translation>
</message>
<message>
<location filename="../ofdscene.cpp" line="91"/>
<source>Selected image: </source>
<translation>Выбранное изображение: </translation>
</message>
<message>
<location filename="../ofdscene.cpp" line="150"/>
<source>Captcha was not solved correctly!</source>
<translation>Капча была решена неверно!</translation>
</message>
<message>
<location filename="../ofdscene.cpp" line="152"/>
<source>Captcha is incorrect</source>
<translation>Капча введена неверно</translation>
</message>
<message>
<location filename="../ofdscene.cpp" line="157"/>
<source>Internal server error. Please, try again later.</source>
<translation>Внутренняя ошибка сервера. Пожалуйста, попробуйте снова позже.</translation>
</message>
<message>
<location filename="../ofdscene.cpp" line="159"/>
<source>Internal server error</source>
<translation>Внутренняя ошибка сервера</translation>
</message>
<message>
<location filename="../ofdscene.cpp" line="164"/>
<source>Check not found. Please, ensure correctness of entered data.</source>
<translation>Чек не найден. Пожалуйста, убедитесь в правильности введённых данных.</translation>
</message>
<message>
<location filename="../ofdscene.cpp" line="166"/>
<source>Check was not found</source>
<translation>Чек не найден</translation>
</message>
<message>
<location filename="../ofdscene.cpp" line="198"/>
<source>QR code for binaryeye to connect</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ofdscene.cpp" line="199"/>
<source>I&apos;ve scanned</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>123 123</source>
<translation type="obsolete">123 123</translation>
</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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></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 type="unfinished"></translation> <translation>Печатать Итого</translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<source>You need to restart program to apply language changes</source>
<translation type="vanished">Требуется перезагрузить программу, чтобы применить изменения языка</translation>
</message>
<message>
<source>Restart required</source>
<translation type="vanished">Требуется перезагрузка</translation>
</message> </message>
</context> </context>
<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 type="unfinished"></translation> <translation>Диалог</translation>
</message> </message>
<message> <message>
<location filename="../solvecaptchadialog.cpp" line="23"/> <location filename="../solvecaptchadialog.cpp" line="23"/>
<source>Please, enter a valid captcha</source> <source>Please, enter a valid captcha</source>
<translation type="unfinished"></translation> <translation>Пожалуйста, введите верную капчу</translation>
</message> </message>
<message> <message>
<location filename="../solvecaptchadialog.cpp" line="25"/> <location filename="../solvecaptchadialog.cpp" line="25"/>
<source>No captcha</source> <source>No captcha</source>
<translation type="unfinished"></translation> <translation>Нет капчи</translation>
</message> </message>
</context> </context>
<context> <context>
<name>settingsdialog</name> <name>settingsdialog</name>
<message> <message>
<location filename="../settingsdialog.ui" line="14"/>
<source>Dialog</source> <source>Dialog</source>
<translation type="unfinished"></translation> <translation type="vanished">Диалог</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="72"/>
<source>Goods name position</source> <source>Goods name position</source>
<translation type="unfinished"></translation> <translation type="vanished">Позиция имени товара</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="79"/>
<source>Goods price per unit alias</source> <source>Goods price per unit alias</source>
<translation type="unfinished"></translation> <translation type="vanished">Алиас цены товара</translation>
</message>
<message>
<source>TextLabel</source>
<translation type="vanished">Язык</translation>
</message>
<message>
<source>en_US</source>
<translation type="vanished">en_US</translation>
</message>
<message>
<source>ru_RU</source>
<translation type="vanished">ru_RU</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="86"/>
<location filename="../settingsdialog.ui" line="217"/>
<source>Choose</source> <source>Choose</source>
<translation type="unfinished"></translation> <translation type="vanished">Выбрать</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="96"/>
<source>Print header</source> <source>Print header</source>
<translation type="unfinished"></translation> <translation type="vanished">Печатать заголовок</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="103"/>
<source>Goods net weight alias</source> <source>Goods net weight alias</source>
<translation type="unfinished"></translation> <translation type="vanished">Алиас массы нетто товара</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="110"/>
<source>Stores modules url</source> <source>Stores modules url</source>
<translation type="unfinished"></translation> <translation type="vanished">URL модулей магазина</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="120"/>
<source>Goods total alias</source> <source>Goods total alias</source>
<translation type="unfinished"></translation> <translation type="vanished">Алиас всего за продукт</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="127"/>
<source>Goods name alias</source> <source>Goods name alias</source>
<translation type="unfinished"></translation> <translation type="vanished">Алиас имени товара</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="137"/>
<source>Goods quantity alias</source> <source>Goods quantity alias</source>
<translation type="unfinished"></translation> <translation type="vanished">Алиас количества товара</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="144"/>
<source>Stores modules directory</source> <source>Stores modules directory</source>
<translation type="unfinished"></translation> <translation type="vanished">Директория модулей магазина</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="157"/>
<source>OFD modules directory</source> <source>OFD modules directory</source>
<translation type="unfinished"></translation> <translation type="vanished">Директория модулей ОФД</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="173"/>
<source>Goods price per unit position</source> <source>Goods price per unit position</source>
<translation type="unfinished"></translation> <translation type="vanished">Позиция центы товара</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="180"/>
<source>Goods net weight position</source> <source>Goods net weight position</source>
<translation type="unfinished"></translation> <translation type="vanished">Позиция массы нетто товара</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="187"/>
<source>OFD modules url</source> <source>OFD modules url</source>
<translation type="unfinished"></translation> <translation type="vanished">URL модулей ОФД</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="197"/>
<source>Goods total position</source> <source>Goods total position</source>
<translation type="unfinished"></translation> <translation type="vanished">Позиция всего за товар</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="204"/>
<source>Goods quantity position</source> <source>Goods quantity position</source>
<translation type="unfinished"></translation> <translation type="vanished">Позиция количества товара</translation>
</message> </message>
<message> <message>
<location filename="../settingsdialog.ui" line="227"/>
<source>Print total</source> <source>Print total</source>
<translation type="unfinished"></translation> <translation type="vanished">Печатать Итого</translation>
</message> </message>
</context> </context>
</TS> </TS>

View File

@@ -1,12 +1,49 @@
#include "utils.h" #include "utils.h"
#include <arpa/inet.h>
#include <codecvt> #include <codecvt>
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
#include <locale> #include <locale>
#include <opencv2/core/mat.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <qrencode.h>
#include <regex> #include <regex>
#include <string> #include <string>
#include "../exceptions/ofdrequestexception.h" #include "../exceptions/ofdrequestexception.h"
#include "settings/settings.h"
#include <QWidget>
#include <fstream>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <opencv2/opencv.hpp>
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());
}
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;
@@ -94,8 +131,9 @@ std::vector<std::wstring> find_in_html(std::string& html, std::string regex, std
it != end; it++) { it != end; it++) {
std::wstring found_entry = from_utf8(it->str()); std::wstring found_entry = from_utf8(it->str());
std::wcout << "Found: " << 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::wcout << "Extracted: " << extracted << std::endl;
parsed.push_back(extracted); parsed.push_back(extracted);
} }
return parsed; return parsed;
@@ -106,11 +144,42 @@ std::vector<std::wstring> find_products_in_html(std::string html) {
} }
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_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> &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 << "Prices: ";
for (auto &price : prices) {
std::wcerr << price << " ";
}
std::cerr << std::endl;
} }
Check parseOfdRuAnswer(std::string html) { Check parseOfdRuAnswer(std::string html) {
@@ -124,6 +193,8 @@ Check parseOfdRuAnswer(std::string html) {
if ((products.size() + amounts.size() + prices.size()) == 0) { if ((products.size() + amounts.size() + prices.size()) == 0) {
if (html == "Bad Request4") { // Failed to solve a captcha if (html == "Bad Request4") { // Failed to solve a captcha
throw OfdRequestException("Incorrect captcha"); throw OfdRequestException("Incorrect captcha");
} else if (html.find("500 - Internal server error.") != std::string::npos) {
throw OfdRequestException("Internal server error");
} else { // Most likely that the check does not exist } else { // Most likely that the check does not exist
throw OfdRequestException("Does not exist"); throw OfdRequestException("Does not exist");
} }
@@ -131,6 +202,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, 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);
} }
@@ -144,3 +219,28 @@ Check parseOfdRuAnswer(std::string html) {
return c; return c;
} }
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);
}

View File

@@ -5,6 +5,7 @@
#include <vector> #include <vector>
#include "../check/check.h" #include "../check/check.h"
std::string get_local_ip_address();
std::string to_utf8(std::wstring wide_string); std::string to_utf8(std::wstring wide_string);
std::wstring from_utf8(std::string string); std::wstring from_utf8(std::string string);
@@ -19,4 +20,6 @@ Check parseOfdRuAnswer(std::string);
std::wstring trim_html_response(std::wstring& check); std::wstring trim_html_response(std::wstring& check);
void generate_qr_code(std::string data);
#endif // UTILS_H #endif // UTILS_H