diff --git a/.gitignore b/.gitignore index da3b274..9598828 100644 --- a/.gitignore +++ b/.gitignore @@ -99,7 +99,6 @@ cmake_install.cmake *.moc *.moc.cpp *.qrc.cpp -*.ui # CMake-specific files CMakeCache.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index c611c15..2695750 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,6 +56,7 @@ else() 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 ) diff --git a/adjustpicturedialog.cpp b/adjustpicturedialog.cpp index d6e8d8e..9f50413 100644 --- a/adjustpicturedialog.cpp +++ b/adjustpicturedialog.cpp @@ -58,7 +58,7 @@ std::string AdjustPictureDialog::decode() { cv::cvtColor(im, imGray, cv::COLOR_BGR2GRAY); zbar::Image image(im.cols, im.rows, "Y800", (uchar *) imGray.data, im.cols * im.rows); - int n = scanner.scan(image); + scanner.scan(image); std::string result = ""; @@ -70,3 +70,8 @@ std::string AdjustPictureDialog::decode() { return result; } + +void AdjustPictureDialog::on_contrastSlider_sliderMoved(int position) { + +} + diff --git a/adjustpicturedialog.h b/adjustpicturedialog.h index 7e1e17b..9fefcb2 100644 --- a/adjustpicturedialog.h +++ b/adjustpicturedialog.h @@ -25,6 +25,8 @@ private slots: // void on_buttonBox_accepted(); void accept() override; + void on_contrastSlider_sliderMoved(int position); + private: Ui::AdjustPictureDialog *ui; QGraphicsScene *scene; diff --git a/adjustpicturedialog.ui b/adjustpicturedialog.ui new file mode 100644 index 0000000..3272985 --- /dev/null +++ b/adjustpicturedialog.ui @@ -0,0 +1,115 @@ + + + AdjustPictureDialog + + + + 0 + 0 + 825 + 497 + + + + Dialog + + + + + 450 + 450 + 341 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + 10 + 460 + 591 + 16 + + + + Qt::Horizontal + + + + + + 10 + 0 + 511 + 18 + + + + Please, zoom to qr code and adjust contrast so that qr code looks sharp + + + + + + 15 + 41 + 791 + 391 + + + + buttonBox + label + contrastSlider + graphicsView + + + + ImageRedactor + QGraphicsView +
imageredactor.h
+
+
+ + + + buttonBox + accepted() + AdjustPictureDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + AdjustPictureDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
diff --git a/mainwindow.cpp b/mainwindow.cpp index 324896a..ed3b1cb 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -5,6 +5,7 @@ #include "outputdialog.h" #include "adjustpicturedialog.h" #include "settingsdialog.h" +#include "solvecaptchadialog.h" #include #include #include @@ -46,15 +47,42 @@ void MainWindow::setupStoresList() { #endif } +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::receiveSolvedCaptcha(std::string captcha) { + + std::string check_content = makeRequestToOfd(captcha); + + +} + void MainWindow::on_parseButton_clicked() { QString s; - switch (ui->checkType->currentIndex()) { + 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(); + SolveCaptchaDialog dialog = SolveCaptchaDialog(this); + connect(&dialog, &SolveCaptchaDialog::solvedCaptcha, this, &MainWindow::receiveSolvedCaptcha); + dialog.exec(); + return; } std::wstring check_plaintext = s.toStdWString(); @@ -118,6 +146,12 @@ void MainWindow::onDecodedData(std::string data) { 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() diff --git a/mainwindow.h b/mainwindow.h index e10b92d..92d7c3f 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -26,13 +26,13 @@ public: Check get_check(); void onDecodedData(std::string); + std::string makeRequestToOfd(std::string captcha); + void receiveSolvedCaptcha(std::string); private slots: void on_parseButton_clicked(); void on_storeType_currentIndexChanged(int index); - // void on_chooseImageButton_clicked(); - void on_preferencesButton_clicked(); void on_chooseImageButton_ofd_clicked(); diff --git a/mainwindow.ui b/mainwindow.ui new file mode 100644 index 0000000..7bcc3ce --- /dev/null +++ b/mainwindow.ui @@ -0,0 +1,401 @@ + + + MainWindow + + + + 0 + 0 + 817 + 659 + + + + MainWindow + + + + + + 90 + 10 + 211 + 31 + + + + + + + 10 + 10 + 81 + 31 + + + + Store + + + + + + 30 + 560 + 80 + 26 + + + + Parse + + + + + + 730 + 0 + 81 + 31 + + + + Preferences + + + + + + 10 + 50 + 801 + 511 + + + + 2 + + + + Text + + + + + 0 + 0 + 101 + 18 + + + + Check content + + + + + + 0 + 30 + 611 + 441 + + + + + + + OCR + + + + + 0 + 0 + 80 + 26 + + + + Choose + + + + + + 0 + 60 + 511 + 401 + + + + + + + 100 + 0 + 381 + 18 + + + + Path to image: + + + + + + 0 + 30 + 571 + 18 + + + + Here is recognised check text. Please, edit it if something's wrong: + + + + + + 490 + 10 + 291 + 421 + + + + + + + + + + OFD + + + + + 490 + 10 + 291 + 421 + + + + + + + + + + 100 + 0 + 381 + 18 + + + + Path to image: + + + + + + 10 + 0 + 80 + 26 + + + + Choose + + + + + + 180 + 50 + 261 + 26 + + + + 0000000000000000 + + + + + + 10 + 50 + 161 + 21 + + + + + 0 + 0 + + + + FN (Fiscal Number) + + + + + + 10 + 90 + 161 + 21 + + + + + 0 + 0 + + + + FD (Fiscal Document) + + + + + + 180 + 90 + 261 + 26 + + + + 0000000000 + + + + + + 10 + 130 + 161 + 21 + + + + + 0 + 0 + + + + FI (Fiscal Identifier) + + + + + + 180 + 130 + 261 + 26 + + + + 0000000000 + + + + + + 10 + 170 + 194 + 27 + + + + + + + 10 + 210 + 191 + 26 + + + + + Funds income + + + + + Funds return + + + + + Funds spend + + + + + Spends return + + + + + + + 90 + 250 + 113 + 26 + + + + + + + + + + 10 + 250 + 66 + 18 + + + + Total + + + + + + + + + 0 + 0 + 817 + 23 + + + + + checks parser + + + + + + + + + diff --git a/nano.42371.save b/nano.42371.save new file mode 100644 index 0000000..f8de794 --- /dev/null +++ b/nano.42371.save @@ -0,0 +1,6 @@ +t=20240828T2033 +s=895.50 +fn=7380440700069236 +i=21386 +fp=1292383731 +n=1 diff --git a/net/net.cpp b/net/net.cpp index ecf88bc..bed4d21 100644 --- a/net/net.cpp +++ b/net/net.cpp @@ -1,5 +1,6 @@ #include "net.h" #include +#include "../utils/utils.h" #include #include #include @@ -32,6 +33,12 @@ void write_modules(void *buffer, size_t size, size_t nmemb, void *modules) { } } +size_t writeCallback(void* contents, size_t size, size_t nmemb, void* userp) { + size_t totalSize = size * nmemb; + ((std::string*)userp)->append(std::string((char*)contents)); + return totalSize; +} + std::vector Net::get_all_modules(std::string url) { CURL *handle = curl_easy_init(); @@ -47,7 +54,7 @@ std::vector Net::get_all_modules(std::string url) { return modules; } -std::string Net::get_file(std::string url, std::string filename) { +void Net::get_file(std::string url, std::string filename) { CURL *handle = curl_easy_init(); curl_easy_setopt(handle, CURLOPT_URL, url.c_str()); @@ -58,6 +65,45 @@ std::string Net::get_file(std::string url, std::string filename) { auto success = curl_easy_perform(handle); curl_easy_cleanup(handle); - - return ""; +} + +std::string Net::fetch_check_data_from_ofdru(std::string fn, std::string fd, std::string fi, std::string datetime, int operation, int total, std::string captcha) { + CURL *handle = curl_easy_init(); + if (handle == nullptr) { + std::cerr << "cannot initialize curl" << std::endl; + return ""; + } + struct curl_slist *headers = NULL; + std::string readBuffer = ""; + + curl_easy_setopt(handle, CURLOPT_URL, "https://check.ofd.ru/Document/FetchReceiptFromFns"); + + headers = curl_slist_append(headers, "Content-Type: application/json;charset=UTF-8"); + curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers); + + std::string dataJSON = + "{" + "\"TotalSum\":" + std::to_string(total) + "," + "\"FnNumber\":\"" + fn + "\"," + "\"ReceiptOperationType\":\"" + std::to_string(operation) + "\"," + "\"DocNumber\":\"" + fd + "\"," + "\"DocFiscalSign\":\"" + fi + "\"," + "\"Captcha\":\"" + captcha + "\"," + "\"DocDateTime\":\"" + datetime + ".000Z\"" + "}"; + + curl_easy_setopt(handle, CURLOPT_POSTFIELDS, dataJSON.c_str()); + curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, writeCallback); + curl_easy_setopt(handle, CURLOPT_WRITEDATA, &readBuffer); + + auto answer = curl_easy_perform(handle); + + delete headers; + curl_easy_cleanup(handle); + + return readBuffer; +} + +void Net::get_captcha_from_ofdru() { + get_file("https://check.ofd.ru/api/captcha/common/img", get_path_relative_to_home(".local/share/checks_parser/captcha.png")); } diff --git a/net/net.h b/net/net.h index d2ff34b..5ce64e9 100644 --- a/net/net.h +++ b/net/net.h @@ -11,7 +11,9 @@ class Net public: Net(); std::vector get_all_modules(std::string url); - std::string get_file(std::string url, std::string filename); + void get_file(std::string url, std::string filename); + std::string fetch_check_data_from_ofdru(std::string fn, std::string fd, std::string fi, std::string datetime, int operation, int total, std::string captcha); + void get_captcha_from_ofdru(); }; #endif // NET_H diff --git a/outputdialog.ui b/outputdialog.ui new file mode 100644 index 0000000..f09f5da --- /dev/null +++ b/outputdialog.ui @@ -0,0 +1,215 @@ + + + OutputDialog + + + + 0 + 0 + 586 + 431 + + + + Dialog + + + + + 410 + 390 + 166 + 26 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + 10 + 20 + 271 + 18 + + + + Path to export: + + + + + + 290 + 20 + 80 + 26 + + + + Choose + + + + + + 10 + 50 + 111 + 24 + + + + Print header + + + + + + 10 + 130 + 401 + 221 + + + + + Goods name + + + + + Goods price + + + + + Goods quantity + + + + + Goods net weight + + + + + Goods total + + + + + position + + + + + name + + + + + 1 + + + + + Name + + + + + 2 + + + + + Price + + + + + 3 + + + + + Quantity + + + + + 4 + + + + + Net weight + + + + + 5 + + + + + Total price + + + + + + + 10 + 90 + 111 + 24 + + + + Print total + + + + + + + buttonBox + accepted() + OutputDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + OutputDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + 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/solvecaptchadialog.cpp b/solvecaptchadialog.cpp new file mode 100644 index 0000000..a30c090 --- /dev/null +++ b/solvecaptchadialog.cpp @@ -0,0 +1,33 @@ +#include "solvecaptchadialog.h" +#include "ui_solvecaptchadialog.h" +#include "utils/utils.h" + +#include + +SolveCaptchaDialog::SolveCaptchaDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::SolveCaptchaDialog) { + ui->setupUi(this); + + QString captcha_path = QString::fromStdString(get_path_relative_to_home(".local/share/checks_parser/captcha.png")); + ui->captcha_picture->setPixmap(captcha_path); + ui->captcha_picture->setScaledContents(true); +} + +void SolveCaptchaDialog::accept() { + std::string userInput = ui->captcha_edit->text().toStdString(); + if (userInput.length() < 6) { + QMessageBox infoDialog; + infoDialog.setText("Please, enter a valid captcha"); + infoDialog.setIcon(QMessageBox::Warning); + infoDialog.setWindowTitle("No captcha"); + infoDialog.exec(); + } else { + emit solvedCaptcha(userInput); + QDialog::accept(); + } +} + +SolveCaptchaDialog::~SolveCaptchaDialog() { + delete ui; +} diff --git a/solvecaptchadialog.h b/solvecaptchadialog.h new file mode 100644 index 0000000..8b0555e --- /dev/null +++ b/solvecaptchadialog.h @@ -0,0 +1,30 @@ +#ifndef SOLVECAPTCHADIALOG_H +#define SOLVECAPTCHADIALOG_H + +#include + +namespace Ui { +class SolveCaptchaDialog; +} + +class SolveCaptchaDialog : public QDialog +{ + Q_OBJECT + +public: + explicit SolveCaptchaDialog(QWidget *parent = nullptr); + ~SolveCaptchaDialog(); + + +signals: + void solvedCaptcha(std::string); + + +private: + Ui::SolveCaptchaDialog *ui; + +private slots: + void accept() override; +}; + +#endif // SOLVECAPTCHADIALOG_H diff --git a/solvecaptchadialog.ui b/solvecaptchadialog.ui new file mode 100644 index 0000000..c587811 --- /dev/null +++ b/solvecaptchadialog.ui @@ -0,0 +1,91 @@ + + + SolveCaptchaDialog + + + + 0 + 0 + 503 + 350 + + + + Dialog + + + + + 130 + 310 + 341 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + 20 + 20 + 451 + 221 + + + + + + + + + + 80 + 260 + 321 + 26 + + + + + + + + buttonBox + accepted() + SolveCaptchaDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + SolveCaptchaDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + +