diff --git a/.gitignore b/.gitignore index fc17f90..6f7bd4f 100644 --- a/.gitignore +++ b/.gitignore @@ -75,3 +75,6 @@ CMakeLists.txt.user* #Build build build/ +*.AppImage +*.appimage + diff --git a/CMakeLists.txt b/CMakeLists.txt index 23b6bc8..5c630a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,13 +43,17 @@ else() check/check.h check/check.cpp parser/parser.h parser/parser.cpp parser/module.h parser/module.cpp - settings.h + outputdialog.h outputdialog.cpp outputdialog.ui output/output_options.h output/output_options.cpp ofd/ofd.h ofd/ofd.cpp ofd/module.h ofd/module.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 + ) endif() endif() diff --git a/CMakeLists.txt.user b/CMakeLists.txt.user index d48a13b..76dd4af 100644 --- a/CMakeLists.txt.user +++ b/CMakeLists.txt.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -102,14 +102,14 @@ 2 false - -DCMAKE_BUILD_TYPE:STRING=Debug --DCMAKE_GENERATOR:STRING=Ninja --DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} --DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} --DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} + -DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} -DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake +-DCMAKE_GENERATOR:STRING=Ninja +-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} -DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} --DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} +-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} +-DCMAKE_BUILD_TYPE:STRING=Debug +-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} 0 /home/leca/projects/qt/checks-parser/build/Desktop-Debug @@ -159,14 +159,14 @@ 2 false - -DCMAKE_BUILD_TYPE:STRING=Release --DCMAKE_GENERATOR:STRING=Ninja --DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} --DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} --DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} + -DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} -DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake +-DCMAKE_GENERATOR:STRING=Ninja +-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} -DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} --DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} +-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} +-DCMAKE_BUILD_TYPE:STRING=Release +-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} /home/leca/projects/qt/checks-parser/build/Desktop-Release @@ -213,14 +213,14 @@ 2 false - -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo --DCMAKE_GENERATOR:STRING=Ninja --DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} --DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} --DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} + -DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} -DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake +-DCMAKE_GENERATOR:STRING=Ninja +-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} -DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} --DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} +-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} +-DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo +-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} /home/leca/projects/qt/checks-parser/build/Desktop-RelWithDebInfo @@ -267,14 +267,14 @@ 2 false - -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo --DCMAKE_GENERATOR:STRING=Ninja --DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} --DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} --DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} + -DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} -DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake +-DCMAKE_GENERATOR:STRING=Ninja +-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} -DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} --DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} +-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} +-DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo +-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} 0 /home/leca/projects/qt/checks-parser/build/Desktop-Profile @@ -322,14 +322,14 @@ 2 false - -DCMAKE_BUILD_TYPE:STRING=MinSizeRel --DCMAKE_GENERATOR:STRING=Ninja --DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} --DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} --DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} + -DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} -DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake +-DCMAKE_GENERATOR:STRING=Ninja +-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} -DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} --DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} +-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} +-DCMAKE_BUILD_TYPE:STRING=MinSizeRel +-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} /home/leca/projects/qt/checks-parser/build/Desktop-MinSizeRel @@ -402,7 +402,7 @@ true true true - /home/leca/projects/qt/checks-parser/build/Desktop-Debug + /home/leca/projects/qt/checks-parser/build/Desktop-Debug/bin 1 diff --git a/TODO b/TODO index 4417d4d..3578955 100644 --- a/TODO +++ b/TODO @@ -7,5 +7,7 @@ Complete module "image-to-text": Add features: autodetect store type auto download of stores modules + auto download of ofd modules + settings, a window for editing settings. Refactor: Get rid of CPR, use libcurl instead diff --git a/Docker/archlinux/Dockerfile b/deploy/Docker/archlinux/Dockerfile similarity index 100% rename from Docker/archlinux/Dockerfile rename to deploy/Docker/archlinux/Dockerfile diff --git a/Docker/debian/Dockerfile b/deploy/Docker/debian/Dockerfile similarity index 100% rename from Docker/debian/Dockerfile rename to deploy/Docker/debian/Dockerfile diff --git a/deploy/appimage/AppDir/.DirIcon b/deploy/appimage/AppDir/.DirIcon new file mode 120000 index 0000000..ef2a0f2 --- /dev/null +++ b/deploy/appimage/AppDir/.DirIcon @@ -0,0 +1 @@ +checks-parser.png \ No newline at end of file diff --git a/deploy/appimage/AppDir/AppRun b/deploy/appimage/AppDir/AppRun new file mode 120000 index 0000000..78283d7 --- /dev/null +++ b/deploy/appimage/AppDir/AppRun @@ -0,0 +1 @@ +usr/bin/checks-parser \ No newline at end of file diff --git a/deploy/appimage/AppDir/checks-parser.desktop b/deploy/appimage/AppDir/checks-parser.desktop new file mode 100644 index 0000000..afffa7a --- /dev/null +++ b/deploy/appimage/AppDir/checks-parser.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Name=Checks parser +Type=Application +Terminal=false +NoDisplay=false +Exec=checks-parser +Categories=Utility; +Icon=checks-parser diff --git a/deploy/appimage/AppDir/checks-parser.png b/deploy/appimage/AppDir/checks-parser.png new file mode 100644 index 0000000..869f820 Binary files /dev/null and b/deploy/appimage/AppDir/checks-parser.png differ diff --git a/deploy/appimage/AppDir/usr/bin/checks-parser b/deploy/appimage/AppDir/usr/bin/checks-parser new file mode 100755 index 0000000..c2471be Binary files /dev/null and b/deploy/appimage/AppDir/usr/bin/checks-parser differ diff --git a/main.cpp b/main.cpp index 0e713fb..b58fdf7 100644 --- a/main.cpp +++ b/main.cpp @@ -1,7 +1,47 @@ #include "mainwindow.h" +#include "net/net.h" +#include "ofd/ofd.h" +#include "settings/settings.h" +#include "utils/utils.h" #include +#include +#include int main(int argc, char *argv[]) { + curl_global_init(CURL_GLOBAL_ALL); + + std::string settings_file_path = + get_path_relative_to_home(".local/share/checks_parser/settings.json"); + + Settings s(settings_file_path); + OFD ofd; + Net n; + + std::vector ofd_updates = ofd.check_updates(); + for (const std::string &update : ofd_updates) { + std::cout << "Downloading " + << s.get_setting("ofds_modules_url") + update << " to " + << get_path_relative_to_home(s.get_setting("ofds_modules_dir") + + "/" + update) + << std::endl; + n.get_file(s.get_setting("ofds_modules_url") + "/" + update, + get_path_relative_to_home(s.get_setting("ofds_modules_dir") + + "/" + update)); + } + + Parser p; + std::vector stores_updates = p.check_updates();\ + for (const std::string &update : stores_updates) { + std::cout << "Downloading " + << s.get_setting("stores_modules_url") + update << " to " + << get_path_relative_to_home(s.get_setting("stores_modules_dir") + + "/" + update) + << std::endl; + + n.get_file(s.get_setting("stores_modules_url") + "/" + update, + get_path_relative_to_home(s.get_setting("stores_modules_dir") + + "/" + update)); + } QApplication a(argc, argv); MainWindow w; diff --git a/mainwindow.cpp b/mainwindow.cpp index a076d20..7c5f6d4 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -3,7 +3,7 @@ #include "check/check.h" #include "goods/goods.h" #include "outputdialog.h" -#include "settings.h" +#include "settingsdialog.h" #include #include #include "image/checkimage.h" @@ -67,9 +67,9 @@ void MainWindow::on_parseButton_clicked() { check.add_goods(g); } - OutputDialog *d = new OutputDialog(this, check); - d->show(); - d->exec(); + OutputDialog d = OutputDialog(this, check); + d.show(); + d.exec(); } void MainWindow::on_storeType_currentIndexChanged(int index) { @@ -91,3 +91,10 @@ void MainWindow::on_chooseImageButton_clicked() { ui->checkContentFromImage->setPlainText(QString::fromStdString(parsed)); } + +void MainWindow::on_preferencesButton_clicked() { + SettingsDialog s = SettingsDialog(); + s.show(); + s.exec(); +} + diff --git a/mainwindow.h b/mainwindow.h index 1a6c749..6995ec2 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -33,6 +33,8 @@ private slots: void on_chooseImageButton_clicked(); + void on_preferencesButton_clicked(); + private: Ui::MainWindow *ui; }; diff --git a/mainwindow.ui b/mainwindow.ui index c20959d..4b8482f 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -172,6 +172,19 @@ Parse + + + + 730 + 0 + 81 + 31 + + + + Preferences + + diff --git a/net/net.cpp b/net/net.cpp new file mode 100644 index 0000000..ecf88bc --- /dev/null +++ b/net/net.cpp @@ -0,0 +1,63 @@ +#include "net.h" +#include +#include +#include +#include + +struct data {}; + +size_t write_data(void *buffer, size_t size, size_t nmemb, void *filename) { + FILE *f = fopen(((std::string *)filename)->c_str(), "w"); + size_t written = fwrite(buffer, size, nmemb, f); + + fclose(f); + + return written; +} + +Net::Net() {} + +void write_modules(void *buffer, size_t size, size_t nmemb, void *modules) { + std::vector *modules_vector = + (std::vector *)modules; + std::string to_parse = std::string((char*)buffer); + + std::regex r("(?!\\\")\\w+\\.json(?!\\\")", std::regex::collate); + std::smatch res; + + std::string::const_iterator search(to_parse.cbegin()); + while (std::regex_search(search, to_parse.cend(), res, r)) { + modules_vector->push_back(res[0]); + search = res.suffix().first; + } +} + +std::vector Net::get_all_modules(std::string url) { + CURL *handle = curl_easy_init(); + + curl_easy_setopt(handle, CURLOPT_URL, url.c_str()); + curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_modules); + + std::vector modules {}; + + curl_easy_setopt(handle, CURLOPT_WRITEDATA, &modules); + + curl_easy_perform(handle); + + return modules; +} + +std::string Net::get_file(std::string url, std::string filename) { + CURL *handle = curl_easy_init(); + + curl_easy_setopt(handle, CURLOPT_URL, url.c_str()); + + curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_data); + curl_easy_setopt(handle, CURLOPT_WRITEDATA, &filename); + + auto success = curl_easy_perform(handle); + + curl_easy_cleanup(handle); + + return ""; +} diff --git a/net/net.h b/net/net.h new file mode 100644 index 0000000..d2ff34b --- /dev/null +++ b/net/net.h @@ -0,0 +1,17 @@ +#ifndef NET_H +#define NET_H + +#include +#include + +size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp); + +class Net +{ +public: + Net(); + std::vector get_all_modules(std::string url); + std::string get_file(std::string url, std::string filename); +}; + +#endif // NET_H diff --git a/ofd/ofd.cpp b/ofd/ofd.cpp index 82d92ff..ee3689d 100644 --- a/ofd/ofd.cpp +++ b/ofd/ofd.cpp @@ -1,19 +1,21 @@ #include "ofd.h" -#include "../settings.h" #include "../utils/utils.h" #include #include #include #include +#include "../net/net.h" +#include "../settings/settings.h" OFD::OFD() {} OFD::OFD(std::string path) { this->module = OFDModule(path); }; std::vector OFD::search_ofds() { + Settings s(get_path_relative_to_home(".local/share/checks_parser/settings.json")); std::vector result{}; - std::string path = std::string(std::getenv("HOME")) + "/" + OFDS_MODULES_DIR; + std::string path = get_path_relative_to_home(s.get_setting("ods_modules_dir")); std::filesystem::directory_entry modules_dir(path); if (!modules_dir.exists()) { @@ -35,45 +37,31 @@ void OFD::set_module(std::string path) { this->module = OFDModule(path); } std::string OFD::get_check_data(std::string fn, std::string fd, std::string fp) { - //curl 'https://ofd.beeline.ru/api/ofdcheck/checkf?fn=7281440701327430&fp=2518183888&fd=25955&format=4' \ - -H 'Accept: application/json, text/plain, */*' \ - -H 'Accept-Language: en-US,en;q=0.9,eo;q=0.8,ru;q=0.7' \ - -H 'Authorization: bearer null' \ - -H 'Connection: keep-alive' \ - -H 'Content-Type: application/json' \ - -H 'DNT: 1' \ - -H 'Referer: https://ofd.beeline.ru/check-order?fn=7281440701327430&fp=2518183888&fd=25955' \ - -H 'Sec-Fetch-Dest: empty' \ - -H 'Sec-Fetch-Mode: cors' \ - -H 'Sec-Fetch-Site: same-origin' \ - -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36' \ - -H 'sec-ch-ua: "Chromium";v="127", "Not)A;Brand";v="99"' \ - -H 'sec-ch-ua-mobile: ?0' \ - -H 'sec-ch-ua-platform: "Linux"' - - // curl 'https://ofd.beeline.ru/api/ofdcheck/checkf?fn=7281440701327430&fp=2807139546&fd=25051&format=4' \ - -H 'Accept: application/json, text/plain, */*' \ - -H 'Accept-Language: en-US,en;q=0.9,eo;q=0.8,ru;q=0.7' \ - -H 'Authorization: bearer null' \ - -H 'Connection: keep-alive' \ - -H 'Content-Type: application/json' \ - -H 'DNT: 1' \ - -H 'Referer: https://ofd.beeline.ru/check-order?fn=7281440701327430&fp=2807139546&fd=25051' \ - -H 'Sec-Fetch-Dest: empty' \ - -H 'Sec-Fetch-Mode: cors' \ - -H 'Sec-Fetch-Site: same-origin' \ - -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36' \ - -H 'sec-ch-ua: "Chromium";v="127", "Not)A;Brand";v="99"' \ - -H 'sec-ch-ua-mobile: ?0' \ - -H 'sec-ch-ua-platform: "Linux"' - - // // cpr::Response r = cpr::Get(cpr::Url{"https://httpbin.org/get"}); - // std::cout << fn << " " << fd << " " << fp << std::endl; - // cpr::Response r = - // //to_utf8(module.get_url()) - // cpr::Get(cpr::Url{"https://ofd.beeline.ru/api/ofdcheck/checkf"}, - // cpr::Parameters{{"fn", fn}, {"fd", fd}, {"fp", fp}, {"format", "4"}}); - - // return r.text; + //TODO return ""; } + +std::vector OFD::check_updates() { + Settings s(get_path_relative_to_home(".local/share/checks_parser/settings.json")); + + std::string path = get_path_relative_to_home(s.get_setting("ofds_modules_dir")); + std::vector to_download; + std::vector stored_modules; + + for (const auto& file : std::filesystem::directory_iterator(path)) { + if (!file.is_regular_file()) continue; + stored_modules.push_back(file.path().filename()); + std::cout << "Detected OFD module" << file.path().filename() << std::endl; + } + Net n; + std::vector remote_modules = n.get_all_modules(s.get_setting("ofds_modules_url")); + + for (const std::string& module : remote_modules) { + if (!vector_contains_element(stored_modules, module)) { + to_download.push_back(module); + std::cout << "I need to download OFD module " << module << std::endl; + } + } + + return to_download; +} diff --git a/ofd/ofd.h b/ofd/ofd.h index 418d4b3..6f98355 100644 --- a/ofd/ofd.h +++ b/ofd/ofd.h @@ -18,5 +18,6 @@ public: void set_module(std::string); std::string get_check_data(std::string fn, std::string fd, std::string fp); + std::vector check_updates(); }; #endif // OFD_H diff --git a/output/output_options.cpp b/output/output_options.cpp index e416dd3..b362305 100644 --- a/output/output_options.cpp +++ b/output/output_options.cpp @@ -10,7 +10,7 @@ void OutputOptions::add_or_update_column(Column &column) { } } -void OutputOptions::update_column(Column& column, unsigned short index) { +void OutputOptions::update_column(Column &column, unsigned short index) { this->order[index] = column; } @@ -38,13 +38,11 @@ bool OutputOptions::column_exist(ColumnType t) { return false; } -Column& OutputOptions::get_column (ColumnType t){ +Column &OutputOptions::get_column(ColumnType t) { return this->order[find_column(t)]; } -std::vector& OutputOptions::get_columns() { - return this->order; -} +std::vector &OutputOptions::get_columns() { return this->order; } void OutputOptions::set_print_header(bool value) { this->print_header = value; } bool OutputOptions::get_print_header() { return this->print_header; } diff --git a/outputdialog.cpp b/outputdialog.cpp index f9b4f97..61e4909 100644 --- a/outputdialog.cpp +++ b/outputdialog.cpp @@ -6,11 +6,35 @@ #include #include #include +#include "settings/settings.h" +#include "utils/utils.h" OutputDialog::OutputDialog(QWidget *parent, Check &check) : QDialog(parent), ui(new Ui::OutputDialog), check(check), - options(*(new OutputOptions())) { + options(OutputOptions()) { + + Settings settings(get_path_relative_to_home(".local/share/checks_parser/settings.json")); + ui->setupUi(this); + + ui->tableWidget->item(0, 0)->setText(QString::fromStdString(settings.get_all_settings()["output_order"]["goods_name"]["name"])); + ui->tableWidget->item(0, 1)->setText(QString::number((int)settings.get_all_settings()["output_order"]["goods_name"]["position"])); + + ui->tableWidget->item(1, 0)->setText(QString::fromStdString(settings.get_all_settings()["output_order"]["goods_price_per_unit"]["name"])); + ui->tableWidget->item(1, 1)->setText(QString::number((int)settings.get_all_settings()["output_order"]["goods_price_per_unit"]["position"])); + + ui->tableWidget->item(2, 0)->setText(QString::fromStdString(settings.get_all_settings()["output_order"]["goods_quantity"]["name"])); + ui->tableWidget->item(2, 1)->setText(QString::number((int)settings.get_all_settings()["output_order"]["goods_quantity"]["position"])); + + ui->tableWidget->item(3, 0)->setText(QString::fromStdString(settings.get_all_settings()["output_order"]["goods_net_weight"]["name"])); + ui->tableWidget->item(3, 1)->setText(QString::number((int)settings.get_all_settings()["output_order"]["goods_net_weight"]["position"])); + + ui->tableWidget->item(4, 0)->setText(QString::fromStdString(settings.get_all_settings()["output_order"]["goods_total"]["name"])); + ui->tableWidget->item(4, 1)->setText(QString::number((int)settings.get_all_settings()["output_order"]["goods_total"]["position"])); + + + ui->printHeaderCheckBox->setChecked(settings.get_all_settings()["print_header"]); + ui->printTotalCheckBox->setChecked(settings.get_all_settings()["print_total"]); } OutputDialog::~OutputDialog() { delete ui; } diff --git a/outputdialog.h b/outputdialog.h index 27664cd..2f9b3a7 100644 --- a/outputdialog.h +++ b/outputdialog.h @@ -3,8 +3,8 @@ #include "check/check.h" #include "output/output_options.h" -#include #include +#include namespace Ui { class OutputDialog; @@ -16,7 +16,6 @@ class OutputDialog : public QDialog { OutputOptions options; Check ✓ - public: explicit OutputDialog(QWidget *parent = nullptr, Check & = *(new Check())); ~OutputDialog(); diff --git a/parser/parser.cpp b/parser/parser.cpp index 49218b7..5e2a731 100644 --- a/parser/parser.cpp +++ b/parser/parser.cpp @@ -1,13 +1,16 @@ #include "parser.h" -#include "../settings.h" +#include "../goods/goods.h" +#include "../net/net.h" +#include "../settings/settings.h" +#include "../utils/utils.h" #include #include -#include "../goods/goods.h" Parser::Parser() {} std::vector Parser::search_modules() { - std::string path = std::string(std::getenv("HOME")) + "/" + STORES_MODULES_DIR; + Settings s(get_path_relative_to_home(".local/share/checks_parser/settings.json")); + std::string path = get_path_relative_to_home(s.get_setting("stores_modules_dir"));//std::string(std::getenv("HOME")) + "/" + STORES_MODULES_DIR; std::filesystem::directory_entry modules_dir(path); if (!modules_dir.exists()) { @@ -38,9 +41,7 @@ std::vector Parser::parse(std::wstring check_plaintext) { std::vector goods_prices = module.parse_price(check_plaintext); std::vector goods_quantities = module.parse_quantity(check_plaintext); -#ifdef DEBUG - std::cout << goods_names.size() << " " << goods_prices.size() << " " << goods_quantities.size() << std::endl; -#endif + if (goods_names.size() != goods_prices.size() || goods_names.size() != goods_quantities.size() || goods_prices.size() != goods_quantities.size()) { @@ -57,3 +58,38 @@ std::vector Parser::parse(std::wstring check_plaintext) { return result; } + +std::vector Parser::check_updates() { + std::cout << "Checking updates for stores modules" << std::endl; + Settings s(get_path_relative_to_home(".local/share/checks_parser/settings.json")); + std::string path = get_path_relative_to_home(s.get_setting("stores_modules_dir")); + + std::vector to_download; + std::vector stored_modules; + + std::filesystem::directory_entry modules_dir(path); + if (!modules_dir.exists()) { + std::filesystem::create_directories(path); + } + for (const auto& file : std::filesystem::directory_iterator(path)) { + if (!file.is_regular_file()) continue; + stored_modules.push_back(file.path().filename()); + std::cout << file.path().filename() << " detected store module" << std::endl; + } + Net n; + std::cerr << "Downloading modules list from: " << s.get_setting("stores_modules_url"); + std::vector remote_modules = n.get_all_modules(s.get_setting("stores_modules_url")); + if (stored_modules.empty()) { + std::cout << "I need to download everything" << std::endl; + to_download = remote_modules; + } else { + for (const std::string& module : remote_modules) { + if (!vector_contains_element(stored_modules, module)) { + std::cout << "I need to download store module " << module << std::endl; + to_download.push_back(module); + } + } + } + + return to_download; +} diff --git a/parser/parser.h b/parser/parser.h index 8b9daf7..5e4136f 100644 --- a/parser/parser.h +++ b/parser/parser.h @@ -1,22 +1,25 @@ #ifndef PARSER_H #define PARSER_H +#include "../goods/goods.h" #include "module.h" #include #include -#include "../goods/goods.h" class Parser { StoreModule module; + public: Parser(); std::vector search_modules(); + std::vector check_updates(); + void set_module(std::string); - std::vector parse (std::wstring); + std::vector parse(std::wstring); }; #endif // PARSER_H diff --git a/settings.h b/settings.h deleted file mode 100644 index 9677971..0000000 --- a/settings.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef SETTINGS_H -#define SETTINGS_H - -#define OFDS_MODULES_DIR ".local/share/checks_parser/modules/ofd" -#define STORES_MODULES_DIR ".local/share/checks_parser/modules/stores" -// #define DEBUG - -#endif // SETTINGS_H diff --git a/settings/settings.cpp b/settings/settings.cpp new file mode 100644 index 0000000..f86a9c2 --- /dev/null +++ b/settings/settings.cpp @@ -0,0 +1,85 @@ +#include "settings.h" +#include +#include +#include +#include + +Settings::Settings(std::string path) { + this->settings_file_path = path; + + if (!std::filesystem::exists(path)) { + std::ofstream output(path); + + nlohmann::json settings = R"({ + "ofds_modules_dir":".local/share/checks_parser/modules/ofd", + "stores_modules_dir":".local/share/checks_parser/modules/stores", + "ofds_modules_url":"https://foxarmy.org/checks-parser/modules/ofd/", + "stores_modules_url":"https://foxarmy.org/checks-parser/modules/modules/", + "print_header": true, + "print_total": true, + "output_order": { + "goods_name": { + "position":1, + "name":"Goods name" + }, + "goods_price_per_unit": { + "position":2, + "name":"Goods price per unit" + }, + "goods_quantity": { + "position":3, + "name":"Goods quantity" + }, + "goods_net_weight": { + "position":4, + "name":"Goods net weight" + }, + "goods_total": { + "position":5, + "name":"Goods total" + } + } + })"_json; + + output << settings; + output.flush(); + output.close(); + this->settings = settings; + } else { + std::ifstream input(path); + + nlohmann::json settings = nlohmann::json::parse(input); + this->settings = settings; + } +} + +void Settings::write_setting(std::string setting, std::string value) { + std::ofstream output(this->settings_file_path, std::fstream::trunc); + + this->settings[setting] = value; + + output << this->settings; +} +std::string Settings::get_setting(std::string setting) { + return this->settings[setting]; +} + +void Settings::set_settings_file_path(std::string path) { + this->settings_file_path = path; +} + +std::string Settings::get_settings_file_path() { + return this->settings_file_path; +} + +nlohmann::json& Settings::get_all_settings() { return this->settings; } + +void Settings::alter_setting(std::string setting, std::string value) { + this->settings[setting] = value; +} + +void Settings::flush() { + std::ofstream output(this->settings_file_path, std::fstream::trunc); + + output << this->settings; +} diff --git a/settings/settings.h b/settings/settings.h new file mode 100644 index 0000000..9f1f137 --- /dev/null +++ b/settings/settings.h @@ -0,0 +1,28 @@ +#ifndef SETTINGS_H +#define SETTINGS_H + +#include +#include + +class Settings { + + std::string settings_file_path; + nlohmann::json settings; + +public: + Settings(std::string path); + //Immediately saves to a file + void write_setting(std::string setting, std::string value); + //Waits for a flush + void alter_setting(std::string setting, std::string value); + std::string get_setting(std::string setting); + + void set_settings_file_path(std::string path); + std::string get_settings_file_path(); + + nlohmann::json& get_all_settings(); + + void flush(); +}; + +#endif // SETTINGS_H diff --git a/settingsdialog.cpp b/settingsdialog.cpp new file mode 100644 index 0000000..d21e8f6 --- /dev/null +++ b/settingsdialog.cpp @@ -0,0 +1,125 @@ +#include "settingsdialog.h" +#include "settings/settings.h" +#include "ui_settingsdialog.h" +#include "utils/utils.h" +#include + +SettingsDialog::SettingsDialog(QWidget *parent) + : QDialog(parent), ui(new Ui::settingsdialog), + settings(Settings(get_path_relative_to_home( + ".local/share/checks_parser/settings.json"))) { + + ui->setupUi(this); + + ui->OFDModulesDirEdit->setText(QString::fromStdString(settings.get_all_settings()["ofds_modules_dir"])); + ui->OFDModulesURLEdit->setText(QString::fromStdString(settings.get_all_settings()["ofds_modules_url"])); + ui->storesModulesDirEdit->setText(QString::fromStdString(settings.get_all_settings()["stores_modules_dir"])); + ui->storesModulesURLEdit->setText(QString::fromStdString(settings.get_all_settings()["stores_modules_url"])); + + ui->goodsNamePositionSpin->setValue(this->settings.get_all_settings()["output_order"]["goods_name"]["position"]); + ui->goodsNameAliasEdit->setText(QString::fromStdString(this->settings.get_all_settings()["output_order"]["goods_name"]["name"])); + + ui->goodsPricePerUnitPositionSpin->setValue(this->settings.get_all_settings()["output_order"]["goods_price_per_unit"]["position"]); + ui->goodsPricePerUnitAliasEdit->setText(QString::fromStdString(this->settings.get_all_settings()["output_order"]["goods_price_per_unit"]["name"])); + + ui->goodsQuantityPositionSpin->setValue(this->settings.get_all_settings()["output_order"]["goods_quantity"]["position"]); + ui->goodsQuantityAliasEdit->setText(QString::fromStdString(this->settings.get_all_settings()["output_order"]["goods_quantity"]["name"])); + + ui->goodsNetWeightPositionSpin->setValue(this->settings.get_all_settings()["output_order"]["goods_net_weight"]["position"]); + ui->goodsNetWeightAliasEdit->setText(QString::fromStdString(this->settings.get_all_settings()["output_order"]["goods_net_weight"]["name"])); + + ui->goodsTotalPositionSpin->setValue(this->settings.get_all_settings()["output_order"]["goods_total"]["position"]); + ui->goodsTotalAliasEdit->setText(QString::fromStdString(this->settings.get_all_settings()["output_order"]["goods_total"]["name"])); + + ui->printHeaderCheckBox->setChecked(this->settings.get_all_settings()["print_header"]); + ui->printTotalCheckBox->setChecked(this->settings.get_all_settings()["print_total"]); +} + +SettingsDialog::~SettingsDialog() { delete ui; } + +void SettingsDialog::on_OFDModulesDirEdit_editingFinished() { + this->settings.alter_setting("ofds_modules_dir", + ui->OFDModulesDirEdit->text().toStdString()); +} + +void SettingsDialog::on_storesModulesDirEdit_editingFinished() { + this->settings.alter_setting("stores_modules_dir", + ui->storesModulesDirEdit->text().toStdString()); +} + +void SettingsDialog::on_OFDModulesURLEdit_editingFinished() { + this->settings.alter_setting("ofds_modules_url", + ui->OFDModulesURLEdit->text().toStdString()); +} + +void SettingsDialog::on_storesModulesURLEdit_editingFinished() { + this->settings.alter_setting("stores_modules_url", + ui->storesModulesURLEdit->text().toStdString()); +} + +void SettingsDialog::on_goodsNamePositionSpin_valueChanged(int value) { + this->settings.get_all_settings()["output_order"]["goods_name"]["position"] = + value; +} +void SettingsDialog::on_goodsNameAliasEdit_editingFinished() { + this->settings.get_all_settings()["output_order"]["goods_name"]["name"] = + ui->goodsNameAliasEdit->text().toStdString(); +} + +void SettingsDialog::on_goodsPricePerUnitPositionSpin_valueChanged(int value) { + this->settings + .get_all_settings()["output_order"]["goods_price_per_unit"]["position"] = + value; +} + +void SettingsDialog::on_goodsPricePerUnitAliasEdit_editingFinished() { + this->settings.get_all_settings()["output_order"]["goods_price_per_unit"]["name"] = + ui->goodsPricePerUnitAliasEdit->text().toStdString(); +} + +void SettingsDialog::on_goodsQuantityPositionSpin_valueChanged(int value) { + this->settings + .get_all_settings()["output_order"]["goods_quantity"]["position"] = value; +} + +void SettingsDialog::on_goodsQuantityAliasEdit_editingFinished() { + this->settings.get_all_settings()["output_order"]["goods_quantity"]["name"] = + ui->goodsQuantityAliasEdit->text().toStdString(); +} + +void SettingsDialog::on_goodsNetWeightPositionSpin_valueChanged(int value) { + this->settings + .get_all_settings()["output_order"]["goods_net_weight"]["position"] = + value; +} + +void SettingsDialog::on_goodsNetWeightAliasEdit_editingFinished() { + this->settings.get_all_settings()["output_order"]["goods_net_weight"]["name"] = + ui->goodsNetWeightAliasEdit->text().toStdString(); +} + + +void SettingsDialog::on_goodsTotalPositionSpin_valueChanged(int value) { + this->settings + .get_all_settings()["output_order"]["goods_total"]["position"] = + value; +} + +void SettingsDialog::on_goodsTotalAliasEdit_editingFinished() { + this->settings.get_all_settings()["output_order"]["goods_total"]["name"] = + ui->goodsTotalAliasEdit->text().toStdString(); +} + +void SettingsDialog::on_printHeaderCheckBox_stateChanged(int value) { + this->settings.get_all_settings()["print_header"] = (value? true : false); +} + +void SettingsDialog::on_printTotalCheckBox_stateChanged(int value) { + this->settings.get_all_settings()["print_total"] = (value? true : false); +} + +void SettingsDialog::on_buttonBox_accepted() { this->settings.flush(); } + +void SettingsDialog::on_buttonBox_rejected() { this->close(); } + + diff --git a/settingsdialog.h b/settingsdialog.h new file mode 100644 index 0000000..7eade0e --- /dev/null +++ b/settingsdialog.h @@ -0,0 +1,59 @@ +#ifndef SETTINGSDIALOG_H +#define SETTINGSDIALOG_H + +#include +#include "settings/settings.h" + +namespace Ui { +class settingsdialog; +} + +class SettingsDialog : public QDialog { + Q_OBJECT + Settings settings; +public: + explicit SettingsDialog(QWidget *parent = nullptr); + ~SettingsDialog(); + +private slots: + void on_OFDModulesDirEdit_editingFinished(); + + void on_buttonBox_accepted(); + + void on_storesModulesDirEdit_editingFinished(); + + void on_OFDModulesURLEdit_editingFinished(); + + void on_storesModulesURLEdit_editingFinished(); + + void on_goodsNamePositionSpin_valueChanged(int arg1); + + void on_goodsNameAliasEdit_editingFinished(); + + void on_goodsPricePerUnitPositionSpin_valueChanged(int arg1); + + void on_goodsPricePerUnitAliasEdit_editingFinished(); + + void on_goodsQuantityPositionSpin_valueChanged(int arg1); + + void on_goodsQuantityAliasEdit_editingFinished(); + + void on_goodsNetWeightPositionSpin_valueChanged(int arg1); + + void on_goodsNetWeightAliasEdit_editingFinished(); + + void on_goodsTotalPositionSpin_valueChanged(int arg1); + + void on_goodsTotalAliasEdit_editingFinished(); + + void on_printHeaderCheckBox_stateChanged(int arg1); + + void on_printTotalCheckBox_stateChanged(int arg1); + + void on_buttonBox_rejected(); + +private: + Ui::settingsdialog *ui; +}; + +#endif // SETTINGSDIALOG_H diff --git a/settingsdialog.ui b/settingsdialog.ui new file mode 100644 index 0000000..c6379b8 --- /dev/null +++ b/settingsdialog.ui @@ -0,0 +1,285 @@ + + + settingsdialog + + + + 0 + 0 + 599 + 727 + + + + Dialog + + + + + 310 + 690 + 251 + 32 + + + + Qt::Orientation::Horizontal + + + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Save + + + + + + 10 + 0 + 541 + 661 + + + + true + + + + + 0 + 0 + 539 + 659 + + + + + + 0 + 0 + 531 + 651 + + + + + + + + + + + + + Goods name position + + + + + + + Goods price per unit alias + + + + + + + Choose + + + + + + + + + + Print header + + + + + + + Goods net weight alias + + + + + + + Stores modules url + + + + + + + + + + Goods total alias + + + + + + + Goods name alias + + + + + + + + + + Goods quantity alias + + + + + + + Stores modules directory + + + + + + + + + + + + + OFD modules directory + + + + + + + + + + + + + + + + Goods price per unit position + + + + + + + Goods net weight position + + + + + + + OFD modules url + + + + + + + + + + Goods total position + + + + + + + Goods quantity position + + + + + + + + + + + + + Choose + + + + + + + + + + Print total + + + + + + + + + + + + + + + + + + + + + + + + + + buttonBox + accepted() + settingsdialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + settingsdialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/utils/utils.cpp b/utils/utils.cpp index 262f8d2..fbd5e44 100644 --- a/utils/utils.cpp +++ b/utils/utils.cpp @@ -1,8 +1,8 @@ #include "utils.h" #include -#include #include +#include std::string to_utf8(std::wstring wide_string) { static std::wstring_convert> utf8_conv; @@ -13,3 +13,18 @@ std::wstring from_utf8(std::string string) { static std::wstring_convert> utf8_conv; return utf8_conv.from_bytes(string); } + +std::string get_path_relative_to_home(std::string path) { + return std::string(std::getenv("HOME")) + "/" + path; +} + +template +bool vector_contains_element(const std::vector& vector, const T& to_find) { + for (const T& element : vector) { + if (element == to_find) return true; + } + return false; +} + +//ужас +template bool vector_contains_element(const std::vector& vector, const std::string& to_find); diff --git a/utils/utils.h b/utils/utils.h index 39324c0..8d5d1d0 100644 --- a/utils/utils.h +++ b/utils/utils.h @@ -2,8 +2,14 @@ #define UTILS_H #include +#include std::string to_utf8(std::wstring wide_string); std::wstring from_utf8(std::string string); +std::string get_path_relative_to_home(std::string path); + +template +bool vector_contains_element(const std::vector &vector, const T &to_find); + #endif // UTILS_H